167754Smsmith/*- 267754Smsmith * Copyright (c) 2005-2006 Robert N. M. Watson 367754Smsmith * All rights reserved. 477424Smsmith * 567754Smsmith * Redistribution and use in source and binary forms, with or without 667754Smsmith * modification, are permitted provided that the following conditions 767754Smsmith * are met: 867754Smsmith * 1. Redistributions of source code must retain the above copyright 967754Smsmith * notice, this list of conditions and the following disclaimer. 1067754Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1167754Smsmith * notice, this list of conditions and the following disclaimer in the 1271867Smsmith * documentation and/or other materials provided with the distribution. 1370243Smsmith * 1467754Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1567754Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1667754Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1767754Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1867754Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1967754Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2067754Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2167754Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2267754Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2367754Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2467754Smsmith * SUCH DAMAGE. 2567754Smsmith * 2667754Smsmith * $FreeBSD$ 2767754Smsmith */ 2867754Smsmith 2967754Smsmith#include <sys/param.h> 3067754Smsmith#include <sys/cpuset.h> 3167754Smsmith#include <sys/sysctl.h> 3267754Smsmith 3367754Smsmith#include <vm/vm.h> 3467754Smsmith#include <vm/vm_page.h> 3567754Smsmith 3667754Smsmith#include <vm/uma.h> 3767754Smsmith#include <vm/uma_int.h> 3867754Smsmith 3967754Smsmith#include <err.h> 4067754Smsmith#include <errno.h> 4167754Smsmith#include <kvm.h> 4267754Smsmith#include <nlist.h> 4367754Smsmith#include <stddef.h> 4467754Smsmith#include <stdio.h> 4567754Smsmith#include <stdlib.h> 4667754Smsmith#include <string.h> 4767754Smsmith#include <unistd.h> 4867754Smsmith 4967754Smsmith#include "memstat.h" 5067754Smsmith#include "memstat_internal.h" 5167754Smsmith 5267754Smsmithstatic struct nlist namelist[] = { 5367754Smsmith#define X_UMA_KEGS 0 5467754Smsmith { .n_name = "_uma_kegs" }, 5567754Smsmith#define X_MP_MAXID 1 5667754Smsmith { .n_name = "_mp_maxid" }, 5767754Smsmith#define X_ALL_CPUS 2 5867754Smsmith { .n_name = "_all_cpus" }, 5967754Smsmith { .n_name = "" }, 6067754Smsmith}; 6167754Smsmith 6267754Smsmith/* 6367754Smsmith * Extract uma(9) statistics from the running kernel, and store all memory 6467754Smsmith * type information in the passed list. For each type, check the list for an 6567754Smsmith * existing entry with the right name/allocator -- if present, update that 6667754Smsmith * entry. Otherwise, add a new entry. On error, the entire list will be 6767754Smsmith * cleared, as entries will be in an inconsistent state. 6867754Smsmith * 6967754Smsmith * To reduce the level of work for a list that starts empty, we keep around a 7067754Smsmith * hint as to whether it was empty when we began, so we can avoid searching 7167754Smsmith * the list for entries to update. Updates are O(n^2) due to searching for 7267754Smsmith * each entry before adding it. 7367754Smsmith */ 7467754Smsmithint 7567754Smsmithmemstat_sysctl_uma(struct memory_type_list *list, int flags) 7667754Smsmith{ 7767754Smsmith struct uma_stream_header *ushp; 7867754Smsmith struct uma_type_header *uthp; 7967754Smsmith struct uma_percpu_stat *upsp; 8067754Smsmith struct memory_type *mtp; 8167754Smsmith int count, hint_dontsearch, i, j, maxcpus, maxid; 8267754Smsmith char *buffer, *p; 8367754Smsmith size_t size; 8467754Smsmith 8567754Smsmith hint_dontsearch = LIST_EMPTY(&list->mtl_list); 8667754Smsmith 8767754Smsmith /* 8867754Smsmith * Query the number of CPUs, number of malloc types so that we can 8967754Smsmith * guess an initial buffer size. We loop until we succeed or really 9067754Smsmith * fail. Note that the value of maxcpus we query using sysctl is not 9167754Smsmith * the version we use when processing the real data -- that is read 9267754Smsmith * from the header. 9367754Smsmith */ 9467754Smsmithretry: 9567754Smsmith size = sizeof(maxid); 9667754Smsmith if (sysctlbyname("kern.smp.maxid", &maxid, &size, NULL, 0) < 0) { 9767754Smsmith if (errno == EACCES || errno == EPERM) 9867754Smsmith list->mtl_error = MEMSTAT_ERROR_PERMISSION; 9967754Smsmith else 10067754Smsmith list->mtl_error = MEMSTAT_ERROR_DATAERROR; 10167754Smsmith return (-1); 10267754Smsmith } 10367754Smsmith if (size != sizeof(maxid)) { 10467754Smsmith list->mtl_error = MEMSTAT_ERROR_DATAERROR; 10567754Smsmith return (-1); 10667754Smsmith } 10767754Smsmith 10867754Smsmith size = sizeof(count); 10967754Smsmith if (sysctlbyname("vm.zone_count", &count, &size, NULL, 0) < 0) { 11067754Smsmith if (errno == EACCES || errno == EPERM) 11167754Smsmith list->mtl_error = MEMSTAT_ERROR_PERMISSION; 11267754Smsmith else 11367754Smsmith list->mtl_error = MEMSTAT_ERROR_VERSION; 11467754Smsmith return (-1); 11567754Smsmith } 11667754Smsmith if (size != sizeof(count)) { 11767754Smsmith list->mtl_error = MEMSTAT_ERROR_DATAERROR; 11867754Smsmith return (-1); 11967754Smsmith } 12067754Smsmith 12177424Smsmith size = sizeof(*uthp) + count * (sizeof(*uthp) + sizeof(*upsp) * 12267754Smsmith (maxid + 1)); 12377424Smsmith 12477424Smsmith buffer = malloc(size); 12567754Smsmith if (buffer == NULL) { 12667754Smsmith list->mtl_error = MEMSTAT_ERROR_NOMEMORY; 12767754Smsmith return (-1); 12867754Smsmith } 12977424Smsmith 13077424Smsmith if (sysctlbyname("vm.zone_stats", buffer, &size, NULL, 0) < 0) { 13177424Smsmith /* 13277424Smsmith * XXXRW: ENOMEM is an ambiguous return, we should bound the 13377424Smsmith * number of loops, perhaps. 13477424Smsmith */ 13567754Smsmith if (errno == ENOMEM) { 13667754Smsmith free(buffer); 13767754Smsmith goto retry; 13867754Smsmith } 13967754Smsmith if (errno == EACCES || errno == EPERM) 14067754Smsmith list->mtl_error = MEMSTAT_ERROR_PERMISSION; 14167754Smsmith else 14267754Smsmith list->mtl_error = MEMSTAT_ERROR_VERSION; 14367754Smsmith free(buffer); 14467754Smsmith return (-1); 14567754Smsmith } 14677424Smsmith 14777424Smsmith if (size == 0) { 14877424Smsmith free(buffer); 14977424Smsmith return (0); 15077424Smsmith } 15167754Smsmith 15267754Smsmith if (size < sizeof(*ushp)) { 15367754Smsmith list->mtl_error = MEMSTAT_ERROR_VERSION; 15477424Smsmith free(buffer); 15577424Smsmith return (-1); 15677424Smsmith } 15777424Smsmith p = buffer; 15877424Smsmith ushp = (struct uma_stream_header *)p; 15977424Smsmith p += sizeof(*ushp); 16077424Smsmith 16177424Smsmith if (ushp->ush_version != UMA_STREAM_VERSION) { 16277424Smsmith list->mtl_error = MEMSTAT_ERROR_VERSION; 16377424Smsmith free(buffer); 16477424Smsmith return (-1); 16577424Smsmith } 16677424Smsmith 16767754Smsmith /* 16877424Smsmith * For the remainder of this function, we are quite trusting about 16977424Smsmith * the layout of structures and sizes, since we've determined we have 17067754Smsmith * a matching version and acceptable CPU count. 17167754Smsmith */ 17271867Smsmith maxcpus = ushp->ush_maxcpus; 17367754Smsmith count = ushp->ush_count; 17467754Smsmith for (i = 0; i < count; i++) { 17567754Smsmith uthp = (struct uma_type_header *)p; 17667754Smsmith p += sizeof(*uthp); 17767754Smsmith 17867754Smsmith if (hint_dontsearch == 0) { 17977424Smsmith mtp = memstat_mtl_find(list, ALLOCATOR_UMA, 18077424Smsmith uthp->uth_name); 18167754Smsmith } else 18267754Smsmith mtp = NULL; 18377424Smsmith if (mtp == NULL) 18477424Smsmith mtp = _memstat_mt_allocate(list, ALLOCATOR_UMA, 18567754Smsmith uthp->uth_name, maxid + 1); 18667754Smsmith if (mtp == NULL) { 18777424Smsmith _memstat_mtl_empty(list); 18877424Smsmith free(buffer); 18977424Smsmith list->mtl_error = MEMSTAT_ERROR_NOMEMORY; 19077424Smsmith return (-1); 19167754Smsmith } 19267754Smsmith 19367754Smsmith /* 19467754Smsmith * Reset the statistics on a current node. 19567754Smsmith */ 19667754Smsmith _memstat_mt_reset_stats(mtp, maxid + 1); 19767754Smsmith 19867754Smsmith mtp->mt_numallocs = uthp->uth_allocs; 19967754Smsmith mtp->mt_numfrees = uthp->uth_frees; 20067754Smsmith mtp->mt_failures = uthp->uth_fails; 20167754Smsmith mtp->mt_sleeps = uthp->uth_sleeps; 20267754Smsmith 20367754Smsmith for (j = 0; j < maxcpus; j++) { 20477424Smsmith upsp = (struct uma_percpu_stat *)p; 20567754Smsmith p += sizeof(*upsp); 20667754Smsmith 20767754Smsmith mtp->mt_percpu_cache[j].mtp_free = 20877424Smsmith upsp->ups_cache_free; 20967754Smsmith mtp->mt_free += upsp->ups_cache_free; 21077424Smsmith mtp->mt_numallocs += upsp->ups_allocs; 21177424Smsmith mtp->mt_numfrees += upsp->ups_frees; 21277424Smsmith } 21367754Smsmith 21467754Smsmith mtp->mt_size = uthp->uth_size; 21577424Smsmith mtp->mt_memalloced = mtp->mt_numallocs * uthp->uth_size; 21677424Smsmith mtp->mt_memfreed = mtp->mt_numfrees * uthp->uth_size; 21767754Smsmith mtp->mt_bytes = mtp->mt_memalloced - mtp->mt_memfreed; 21867754Smsmith mtp->mt_countlimit = uthp->uth_limit; 21977424Smsmith mtp->mt_byteslimit = uthp->uth_limit * uthp->uth_size; 22077424Smsmith 22177424Smsmith mtp->mt_count = mtp->mt_numallocs - mtp->mt_numfrees; 22277424Smsmith mtp->mt_zonefree = uthp->uth_zone_free; 22377424Smsmith 22467754Smsmith /* 22567754Smsmith * UMA secondary zones share a keg with the primary zone. To 22667754Smsmith * avoid double-reporting of free items, report keg free 22777424Smsmith * items only in the primary zone. 22867754Smsmith */ 22977424Smsmith if (!(uthp->uth_zone_flags & UTH_ZONE_SECONDARY)) { 23077424Smsmith mtp->mt_kegfree = uthp->uth_keg_free; 23177424Smsmith mtp->mt_free += mtp->mt_kegfree; 23277424Smsmith } 23377424Smsmith mtp->mt_free += mtp->mt_zonefree; 23477424Smsmith } 23577424Smsmith 23677424Smsmith free(buffer); 23767754Smsmith 23867754Smsmith return (0); 23967754Smsmith} 24067754Smsmith 24167754Smsmithstatic int 24267754Smsmithkread(kvm_t *kvm, void *kvm_pointer, void *address, size_t size, 24367754Smsmith size_t offset) 24467754Smsmith{ 24567754Smsmith ssize_t ret; 24667754Smsmith 24767754Smsmith ret = kvm_read(kvm, (unsigned long)kvm_pointer + offset, address, 24867754Smsmith size); 24967754Smsmith if (ret < 0) 25067754Smsmith return (MEMSTAT_ERROR_KVM); 25167754Smsmith if ((size_t)ret != size) 25267754Smsmith return (MEMSTAT_ERROR_KVM_SHORTREAD); 25367754Smsmith return (0); 25467754Smsmith} 25567754Smsmith 25667754Smsmithstatic int 25767754Smsmithkread_string(kvm_t *kvm, const void *kvm_pointer, char *buffer, int buflen) 25867754Smsmith{ 25967754Smsmith ssize_t ret; 26067754Smsmith int i; 26167754Smsmith 26267754Smsmith for (i = 0; i < buflen; i++) { 26367754Smsmith ret = kvm_read(kvm, (unsigned long)kvm_pointer + i, 26467754Smsmith &(buffer[i]), sizeof(char)); 26567754Smsmith if (ret < 0) 26667754Smsmith return (MEMSTAT_ERROR_KVM); 26767754Smsmith if ((size_t)ret != sizeof(char)) 26867754Smsmith return (MEMSTAT_ERROR_KVM_SHORTREAD); 26967754Smsmith if (buffer[i] == '\0') 27067754Smsmith return (0); 27167754Smsmith } 27267754Smsmith /* Truncate. */ 27367754Smsmith buffer[i-1] = '\0'; 27467754Smsmith return (0); 27567754Smsmith} 27667754Smsmith 27767754Smsmithstatic int 27867754Smsmithkread_symbol(kvm_t *kvm, int index, void *address, size_t size, 27967754Smsmith size_t offset) 28067754Smsmith{ 28167754Smsmith ssize_t ret; 28267754Smsmith 28367754Smsmith ret = kvm_read(kvm, namelist[index].n_value + offset, address, size); 28467754Smsmith if (ret < 0) 28577424Smsmith return (MEMSTAT_ERROR_KVM); 28677424Smsmith if ((size_t)ret != size) 28777424Smsmith return (MEMSTAT_ERROR_KVM_SHORTREAD); 28877424Smsmith return (0); 28977424Smsmith} 29077424Smsmith 29177424Smsmith/* 29267754Smsmith * memstat_kvm_uma() is similar to memstat_sysctl_uma(), only it extracts 29371867Smsmith * UMA(9) statistics from a kernel core/memory file. 29467754Smsmith */ 29567754Smsmithint 29667754Smsmithmemstat_kvm_uma(struct memory_type_list *list, void *kvm_handle) 29767754Smsmith{ 29867754Smsmith LIST_HEAD(, uma_keg) uma_kegs; 29967754Smsmith struct memory_type *mtp; 30067754Smsmith struct uma_bucket *ubp, ub; 30167754Smsmith struct uma_cache *ucp, *ucp_array; 30267754Smsmith struct uma_zone *uzp, uz; 30367754Smsmith struct uma_keg *kzp, kz; 30467754Smsmith int hint_dontsearch, i, mp_maxid, ret; 30569450Smsmith char name[MEMTYPE_MAXNAME]; 30667754Smsmith cpuset_t all_cpus; 30767754Smsmith long cpusetsize; 30867754Smsmith kvm_t *kvm; 30967754Smsmith 31067754Smsmith kvm = (kvm_t *)kvm_handle; 31167754Smsmith hint_dontsearch = LIST_EMPTY(&list->mtl_list); 31267754Smsmith if (kvm_nlist(kvm, namelist) != 0) { 31367754Smsmith list->mtl_error = MEMSTAT_ERROR_KVM; 31467754Smsmith return (-1); 31567754Smsmith } 31667754Smsmith if (namelist[X_UMA_KEGS].n_type == 0 || 31767754Smsmith namelist[X_UMA_KEGS].n_value == 0) { 31867754Smsmith list->mtl_error = MEMSTAT_ERROR_KVM_NOSYMBOL; 31967754Smsmith return (-1); 32067754Smsmith } 32167754Smsmith ret = kread_symbol(kvm, X_MP_MAXID, &mp_maxid, sizeof(mp_maxid), 0); 32267754Smsmith if (ret != 0) { 32367754Smsmith list->mtl_error = ret; 32467754Smsmith return (-1); 32567754Smsmith } 32667754Smsmith ret = kread_symbol(kvm, X_UMA_KEGS, &uma_kegs, sizeof(uma_kegs), 0); 32767754Smsmith if (ret != 0) { 32867754Smsmith list->mtl_error = ret; 32967754Smsmith return (-1); 33067754Smsmith } 33167754Smsmith cpusetsize = sysconf(_SC_CPUSET_SIZE); 33267754Smsmith if (cpusetsize == -1 || (u_long)cpusetsize > sizeof(cpuset_t)) { 33367754Smsmith list->mtl_error = MEMSTAT_ERROR_KVM_NOSYMBOL; 33467754Smsmith return (-1); 33567754Smsmith } 33667754Smsmith CPU_ZERO(&all_cpus); 33767754Smsmith ret = kread_symbol(kvm, X_ALL_CPUS, &all_cpus, cpusetsize, 0); 33877424Smsmith if (ret != 0) { 33967754Smsmith list->mtl_error = ret; 34067754Smsmith return (-1); 34167754Smsmith } 34267754Smsmith ucp_array = malloc(sizeof(struct uma_cache) * (mp_maxid + 1)); 34367754Smsmith if (ucp_array == NULL) { 34477424Smsmith list->mtl_error = MEMSTAT_ERROR_NOMEMORY; 34577424Smsmith return (-1); 34677424Smsmith } 34777424Smsmith for (kzp = LIST_FIRST(&uma_kegs); kzp != NULL; kzp = 34877424Smsmith LIST_NEXT(&kz, uk_link)) { 34977424Smsmith ret = kread(kvm, kzp, &kz, sizeof(kz), 0); 35077424Smsmith if (ret != 0) { 35177424Smsmith free(ucp_array); 35277424Smsmith _memstat_mtl_empty(list); 35377424Smsmith list->mtl_error = ret; 35477424Smsmith return (-1); 35577424Smsmith } 35677424Smsmith for (uzp = LIST_FIRST(&kz.uk_zones); uzp != NULL; uzp = 35777424Smsmith LIST_NEXT(&uz, uz_link)) { 35877424Smsmith ret = kread(kvm, uzp, &uz, sizeof(uz), 0); 35977424Smsmith if (ret != 0) { 36077424Smsmith free(ucp_array); 36177424Smsmith _memstat_mtl_empty(list); 36277424Smsmith list->mtl_error = ret; 36377424Smsmith return (-1); 36477424Smsmith } 36567754Smsmith ret = kread(kvm, uzp, ucp_array, 36667754Smsmith sizeof(struct uma_cache) * (mp_maxid + 1), 36767754Smsmith offsetof(struct uma_zone, uz_cpu[0])); 36867754Smsmith if (ret != 0) { 36967754Smsmith free(ucp_array); 37067754Smsmith _memstat_mtl_empty(list); 37167754Smsmith list->mtl_error = ret; 37267754Smsmith return (-1); 37367754Smsmith } 37477424Smsmith ret = kread_string(kvm, uz.uz_name, name, 37577424Smsmith MEMTYPE_MAXNAME); 37677424Smsmith if (ret != 0) { 37777424Smsmith free(ucp_array); 37877424Smsmith _memstat_mtl_empty(list); 37967754Smsmith list->mtl_error = ret; 38067754Smsmith return (-1); 38167754Smsmith } 38277424Smsmith if (hint_dontsearch == 0) { 38377424Smsmith mtp = memstat_mtl_find(list, ALLOCATOR_UMA, 38477424Smsmith name); 38577424Smsmith } else 38677424Smsmith mtp = NULL; 38767754Smsmith if (mtp == NULL) 38867754Smsmith mtp = _memstat_mt_allocate(list, ALLOCATOR_UMA, 38967754Smsmith name, mp_maxid + 1); 39067754Smsmith if (mtp == NULL) { 39167754Smsmith free(ucp_array); 39267754Smsmith _memstat_mtl_empty(list); 39367754Smsmith list->mtl_error = MEMSTAT_ERROR_NOMEMORY; 39467754Smsmith return (-1); 39577424Smsmith } 39667754Smsmith /* 39767754Smsmith * Reset the statistics on a current node. 39877424Smsmith */ 39967754Smsmith _memstat_mt_reset_stats(mtp, mp_maxid + 1); 40067754Smsmith mtp->mt_numallocs = uz.uz_allocs; 40167754Smsmith mtp->mt_numfrees = uz.uz_frees; 40267754Smsmith mtp->mt_failures = uz.uz_fails; 40367754Smsmith mtp->mt_sleeps = uz.uz_sleeps; 40467754Smsmith if (kz.uk_flags & UMA_ZFLAG_INTERNAL) 40567754Smsmith goto skip_percpu; 40667754Smsmith for (i = 0; i < mp_maxid + 1; i++) { 40767754Smsmith if (!CPU_ISSET(i, &all_cpus)) 40867754Smsmith continue; 40967754Smsmith ucp = &ucp_array[i]; 41067754Smsmith mtp->mt_numallocs += ucp->uc_allocs; 41167754Smsmith mtp->mt_numfrees += ucp->uc_frees; 41267754Smsmith 41367754Smsmith if (ucp->uc_allocbucket != NULL) { 41477424Smsmith ret = kread(kvm, ucp->uc_allocbucket, 41577424Smsmith &ub, sizeof(ub), 0); 41667754Smsmith if (ret != 0) { 41767754Smsmith free(ucp_array); 41867754Smsmith _memstat_mtl_empty(list); 41967754Smsmith list->mtl_error = ret; 42067754Smsmith return (-1); 42167754Smsmith } 42267754Smsmith mtp->mt_free += ub.ub_cnt; 42367754Smsmith } 42467754Smsmith if (ucp->uc_freebucket != NULL) { 42577424Smsmith ret = kread(kvm, ucp->uc_freebucket, 42667754Smsmith &ub, sizeof(ub), 0); 42767754Smsmith if (ret != 0) { 42867754Smsmith free(ucp_array); 42967754Smsmith _memstat_mtl_empty(list); 43067754Smsmith list->mtl_error = ret; 43167754Smsmith return (-1); 43267754Smsmith } 43367754Smsmith mtp->mt_free += ub.ub_cnt; 43467754Smsmith } 43577424Smsmith } 43667754Smsmithskip_percpu: 43767754Smsmith mtp->mt_size = kz.uk_size; 43867754Smsmith mtp->mt_memalloced = mtp->mt_numallocs * mtp->mt_size; 43967754Smsmith mtp->mt_memfreed = mtp->mt_numfrees * mtp->mt_size; 44067754Smsmith mtp->mt_bytes = mtp->mt_memalloced - mtp->mt_memfreed; 44167754Smsmith if (kz.uk_ppera > 1) 44267754Smsmith mtp->mt_countlimit = kz.uk_maxpages / 44367754Smsmith kz.uk_ipers; 44467754Smsmith else 44567754Smsmith mtp->mt_countlimit = kz.uk_maxpages * 44667754Smsmith kz.uk_ipers; 44767754Smsmith mtp->mt_byteslimit = mtp->mt_countlimit * mtp->mt_size; 44867754Smsmith mtp->mt_count = mtp->mt_numallocs - mtp->mt_numfrees; 44967754Smsmith for (ubp = LIST_FIRST(&uz.uz_buckets); ubp != 45067754Smsmith NULL; ubp = LIST_NEXT(&ub, ub_link)) { 45167754Smsmith ret = kread(kvm, ubp, &ub, sizeof(ub), 0); 45267754Smsmith mtp->mt_zonefree += ub.ub_cnt; 45367754Smsmith } 45467754Smsmith if (!((kz.uk_flags & UMA_ZONE_SECONDARY) && 45567754Smsmith LIST_FIRST(&kz.uk_zones) != uzp)) { 45667754Smsmith mtp->mt_kegfree = kz.uk_free; 45767754Smsmith mtp->mt_free += mtp->mt_kegfree; 45867754Smsmith } 45977424Smsmith mtp->mt_free += mtp->mt_zonefree; 46077424Smsmith } 46177424Smsmith } 46277424Smsmith free(ucp_array); 46377424Smsmith return (0); 46467754Smsmith} 46567754Smsmith