diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c index d75bd9486eac..5c7dd3760818 100644 --- a/sys/kern/kern_proc.c +++ b/sys/kern/kern_proc.c @@ -142,6 +142,10 @@ uma_zone_t proc_zone; int kstack_pages = KSTACK_PAGES; SYSCTL_INT(_kern, OID_AUTO, kstack_pages, CTLFLAG_RD, &kstack_pages, 0, "Kernel stack size in pages"); +static int vmmap_skip_res_cnt = 0; +SYSCTL_INT(_kern, OID_AUTO, proc_vmmap_skip_resident_count, CTLFLAG_RW, + &vmmap_skip_res_cnt, 0, + "Skip calculation of the pages resident count in kern.proc.vmmap"); CTASSERT(sizeof(struct kinfo_proc) == KINFO_PROC_SIZE); #ifdef COMPAT_FREEBSD32 @@ -2130,6 +2134,66 @@ sysctl_kern_proc_ovmmap(SYSCTL_HANDLER_ARGS) CTASSERT(sizeof(struct kinfo_vmentry) == KINFO_VMENTRY_SIZE); #endif +static void +kern_proc_vmmap_resident(vm_map_t map, vm_map_entry_t entry, + struct kinfo_vmentry *kve) +{ + vm_object_t obj, tobj; + vm_page_t m, m_adv; + vm_offset_t addr; + vm_paddr_t locked_pa; + vm_pindex_t pi, pi_adv, pindex; + + locked_pa = 0; + obj = entry->object.vm_object; + addr = entry->start; + m_adv = NULL; + pi = OFF_TO_IDX(entry->offset + addr - entry->start); + for (; addr < entry->end; addr += IDX_TO_OFF(pi_adv), pi += pi_adv) { + if (m_adv != NULL) { + m = m_adv; + } else { + pi_adv = OFF_TO_IDX(entry->end - addr); + pindex = pi; + for (tobj = obj;; tobj = tobj->backing_object) { + m = vm_page_find_least(tobj, pindex); + if (m != NULL) { + if (m->pindex == pindex) + break; + if (pi_adv > m->pindex - pindex) { + pi_adv = m->pindex - pindex; + m_adv = m; + } + } + if (tobj->backing_object == NULL) + goto next; + pindex += OFF_TO_IDX(tobj-> + backing_object_offset); + } + } + m_adv = NULL; + if (m->psind != 0 && addr + pagesizes[1] <= entry->end && + (addr & (pagesizes[1] - 1)) == 0 && + (pmap_mincore(map->pmap, addr, &locked_pa) & + MINCORE_SUPER) != 0) { + kve->kve_flags |= KVME_FLAG_SUPER; + pi_adv = OFF_TO_IDX(pagesizes[1]); + } else { + /* + * We do not test the found page on validity. + * Either the page is busy and being paged in, + * or it was invalidated. The first case + * should be counted as resident, the second + * is not so clear; we do account both. + */ + pi_adv = 1; + } + kve->kve_resident += pi_adv; +next:; + } + PA_UNLOCK_COND(locked_pa); +} + /* * Must be called with the process locked and will return unlocked. */ @@ -2137,15 +2201,17 @@ int kern_proc_vmmap_out(struct proc *p, struct sbuf *sb) { vm_map_entry_t entry, tmp_entry; - unsigned int last_timestamp; + struct vattr va; + vm_map_t map; + vm_object_t obj, tobj, lobj; char *fullpath, *freepath; struct kinfo_vmentry *kve; - struct vattr va; struct ucred *cred; - int error; struct vnode *vp; struct vmspace *vm; - vm_map_t map; + vm_offset_t addr; + unsigned int last_timestamp; + int error; PROC_LOCK_ASSERT(p, MA_OWNED); @@ -2163,44 +2229,30 @@ kern_proc_vmmap_out(struct proc *p, struct sbuf *sb) vm_map_lock_read(map); for (entry = map->header.next; entry != &map->header; entry = entry->next) { - vm_object_t obj, tobj, lobj; - vm_offset_t addr; - vm_paddr_t locked_pa; - int mincoreinfo; - if (entry->eflags & MAP_ENTRY_IS_SUB_MAP) continue; + addr = entry->end; bzero(kve, sizeof(*kve)); - - kve->kve_private_resident = 0; obj = entry->object.vm_object; if (obj != NULL) { - VM_OBJECT_RLOCK(obj); - if (obj->shadow_count == 1) + for (tobj = obj; tobj != NULL; + tobj = tobj->backing_object) { + VM_OBJECT_RLOCK(tobj); + lobj = tobj; + } + if (obj->backing_object == NULL) kve->kve_private_resident = obj->resident_page_count; - } - kve->kve_resident = 0; - addr = entry->start; - while (addr < entry->end) { - locked_pa = 0; - mincoreinfo = pmap_mincore(map->pmap, addr, &locked_pa); - if (locked_pa != 0) - vm_page_unlock(PHYS_TO_VM_PAGE(locked_pa)); - if (mincoreinfo & MINCORE_INCORE) - kve->kve_resident++; - if (mincoreinfo & MINCORE_SUPER) - kve->kve_flags |= KVME_FLAG_SUPER; - addr += PAGE_SIZE; - } - - for (lobj = tobj = obj; tobj; tobj = tobj->backing_object) { - if (tobj != obj) - VM_OBJECT_RLOCK(tobj); - if (lobj != obj) - VM_OBJECT_RUNLOCK(lobj); - lobj = tobj; + if (!vmmap_skip_res_cnt) + kern_proc_vmmap_resident(map, entry, kve); + for (tobj = obj; tobj != NULL; + tobj = tobj->backing_object) { + if (tobj != obj && tobj != lobj) + VM_OBJECT_RUNLOCK(tobj); + } + } else { + lobj = NULL; } kve->kve_start = entry->start; @@ -2230,7 +2282,7 @@ kern_proc_vmmap_out(struct proc *p, struct sbuf *sb) freepath = NULL; fullpath = ""; - if (lobj) { + if (lobj != NULL) { vp = NULL; switch (lobj->type) { case OBJT_DEFAULT: