1147997Srwatson/*- 2155552Srwatson * Copyright (c) 2005-2006 Robert N. M. Watson 3147997Srwatson * All rights reserved. 4147997Srwatson * 5147997Srwatson * Redistribution and use in source and binary forms, with or without 6147997Srwatson * modification, are permitted provided that the following conditions 7147997Srwatson * are met: 8147997Srwatson * 1. Redistributions of source code must retain the above copyright 9147997Srwatson * notice, this list of conditions and the following disclaimer. 10147997Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11147997Srwatson * notice, this list of conditions and the following disclaimer in the 12147997Srwatson * documentation and/or other materials provided with the distribution. 13147997Srwatson * 14147997Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15147997Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16147997Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17147997Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18147997Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19147997Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20147997Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21147997Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22147997Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23147997Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24147997Srwatson * SUCH DAMAGE. 25147997Srwatson * 26147997Srwatson * $FreeBSD$ 27147997Srwatson */ 28147997Srwatson 29147997Srwatson#include <sys/param.h> 30222813Sattilio#include <sys/cpuset.h> 31147997Srwatson#include <sys/sysctl.h> 32147997Srwatson 33148627Srwatson#include <vm/vm.h> 34148627Srwatson#include <vm/vm_page.h> 35148627Srwatson 36147997Srwatson#include <vm/uma.h> 37148627Srwatson#include <vm/uma_int.h> 38147997Srwatson 39147997Srwatson#include <err.h> 40147997Srwatson#include <errno.h> 41148627Srwatson#include <kvm.h> 42148627Srwatson#include <nlist.h> 43155550Srwatson#include <stddef.h> 44147997Srwatson#include <stdio.h> 45147997Srwatson#include <stdlib.h> 46147997Srwatson#include <string.h> 47222813Sattilio#include <unistd.h> 48147997Srwatson 49147997Srwatson#include "memstat.h" 50147997Srwatson#include "memstat_internal.h" 51147997Srwatson 52148627Srwatsonstatic struct nlist namelist[] = { 53148627Srwatson#define X_UMA_KEGS 0 54148627Srwatson { .n_name = "_uma_kegs" }, 55148627Srwatson#define X_MP_MAXID 1 56148627Srwatson { .n_name = "_mp_maxid" }, 57155547Srwatson#define X_ALL_CPUS 2 58155547Srwatson { .n_name = "_all_cpus" }, 59148627Srwatson { .n_name = "" }, 60148627Srwatson}; 61148627Srwatson 62147997Srwatson/* 63147997Srwatson * Extract uma(9) statistics from the running kernel, and store all memory 64147997Srwatson * type information in the passed list. For each type, check the list for an 65147997Srwatson * existing entry with the right name/allocator -- if present, update that 66147997Srwatson * entry. Otherwise, add a new entry. On error, the entire list will be 67147997Srwatson * cleared, as entries will be in an inconsistent state. 68147997Srwatson * 69147997Srwatson * To reduce the level of work for a list that starts empty, we keep around a 70147997Srwatson * hint as to whether it was empty when we began, so we can avoid searching 71147997Srwatson * the list for entries to update. Updates are O(n^2) due to searching for 72147997Srwatson * each entry before adding it. 73147997Srwatson */ 74147997Srwatsonint 75147997Srwatsonmemstat_sysctl_uma(struct memory_type_list *list, int flags) 76147997Srwatson{ 77147997Srwatson struct uma_stream_header *ushp; 78147997Srwatson struct uma_type_header *uthp; 79147997Srwatson struct uma_percpu_stat *upsp; 80147997Srwatson struct memory_type *mtp; 81224569Spluknet int count, hint_dontsearch, i, j, maxcpus, maxid; 82147997Srwatson char *buffer, *p; 83147997Srwatson size_t size; 84147997Srwatson 85148357Srwatson hint_dontsearch = LIST_EMPTY(&list->mtl_list); 86147997Srwatson 87147997Srwatson /* 88147997Srwatson * Query the number of CPUs, number of malloc types so that we can 89147997Srwatson * guess an initial buffer size. We loop until we succeed or really 90147997Srwatson * fail. Note that the value of maxcpus we query using sysctl is not 91147997Srwatson * the version we use when processing the real data -- that is read 92147997Srwatson * from the header. 93147997Srwatson */ 94147997Srwatsonretry: 95224569Spluknet size = sizeof(maxid); 96224569Spluknet if (sysctlbyname("kern.smp.maxid", &maxid, &size, NULL, 0) < 0) { 97148357Srwatson if (errno == EACCES || errno == EPERM) 98148357Srwatson list->mtl_error = MEMSTAT_ERROR_PERMISSION; 99148357Srwatson else 100148357Srwatson list->mtl_error = MEMSTAT_ERROR_DATAERROR; 101147997Srwatson return (-1); 102147997Srwatson } 103224569Spluknet if (size != sizeof(maxid)) { 104148357Srwatson list->mtl_error = MEMSTAT_ERROR_DATAERROR; 105147997Srwatson return (-1); 106147997Srwatson } 107147997Srwatson 108147997Srwatson size = sizeof(count); 109147997Srwatson if (sysctlbyname("vm.zone_count", &count, &size, NULL, 0) < 0) { 110148357Srwatson if (errno == EACCES || errno == EPERM) 111148357Srwatson list->mtl_error = MEMSTAT_ERROR_PERMISSION; 112148357Srwatson else 113148357Srwatson list->mtl_error = MEMSTAT_ERROR_VERSION; 114147997Srwatson return (-1); 115147997Srwatson } 116147997Srwatson if (size != sizeof(count)) { 117148357Srwatson list->mtl_error = MEMSTAT_ERROR_DATAERROR; 118147997Srwatson return (-1); 119147997Srwatson } 120147997Srwatson 121147997Srwatson size = sizeof(*uthp) + count * (sizeof(*uthp) + sizeof(*upsp) * 122224569Spluknet (maxid + 1)); 123147997Srwatson 124147997Srwatson buffer = malloc(size); 125147997Srwatson if (buffer == NULL) { 126148357Srwatson list->mtl_error = MEMSTAT_ERROR_NOMEMORY; 127147997Srwatson return (-1); 128147997Srwatson } 129147997Srwatson 130147997Srwatson if (sysctlbyname("vm.zone_stats", buffer, &size, NULL, 0) < 0) { 131147997Srwatson /* 132147997Srwatson * XXXRW: ENOMEM is an ambiguous return, we should bound the 133147997Srwatson * number of loops, perhaps. 134147997Srwatson */ 135147997Srwatson if (errno == ENOMEM) { 136147997Srwatson free(buffer); 137147997Srwatson goto retry; 138147997Srwatson } 139148357Srwatson if (errno == EACCES || errno == EPERM) 140148357Srwatson list->mtl_error = MEMSTAT_ERROR_PERMISSION; 141148357Srwatson else 142148357Srwatson list->mtl_error = MEMSTAT_ERROR_VERSION; 143147997Srwatson free(buffer); 144147997Srwatson return (-1); 145147997Srwatson } 146147997Srwatson 147147997Srwatson if (size == 0) { 148147997Srwatson free(buffer); 149147997Srwatson return (0); 150147997Srwatson } 151147997Srwatson 152147997Srwatson if (size < sizeof(*ushp)) { 153148357Srwatson list->mtl_error = MEMSTAT_ERROR_VERSION; 154147997Srwatson free(buffer); 155147997Srwatson return (-1); 156147997Srwatson } 157147997Srwatson p = buffer; 158147997Srwatson ushp = (struct uma_stream_header *)p; 159147997Srwatson p += sizeof(*ushp); 160147997Srwatson 161147997Srwatson if (ushp->ush_version != UMA_STREAM_VERSION) { 162148357Srwatson list->mtl_error = MEMSTAT_ERROR_VERSION; 163147997Srwatson free(buffer); 164147997Srwatson return (-1); 165147997Srwatson } 166147997Srwatson 167147997Srwatson /* 168147997Srwatson * For the remainder of this function, we are quite trusting about 169147997Srwatson * the layout of structures and sizes, since we've determined we have 170147997Srwatson * a matching version and acceptable CPU count. 171147997Srwatson */ 172147997Srwatson maxcpus = ushp->ush_maxcpus; 173147997Srwatson count = ushp->ush_count; 174147997Srwatson for (i = 0; i < count; i++) { 175147997Srwatson uthp = (struct uma_type_header *)p; 176147997Srwatson p += sizeof(*uthp); 177147997Srwatson 178147997Srwatson if (hint_dontsearch == 0) { 179147997Srwatson mtp = memstat_mtl_find(list, ALLOCATOR_UMA, 180147997Srwatson uthp->uth_name); 181147997Srwatson } else 182147997Srwatson mtp = NULL; 183147997Srwatson if (mtp == NULL) 184148354Srwatson mtp = _memstat_mt_allocate(list, ALLOCATOR_UMA, 185224569Spluknet uthp->uth_name, maxid + 1); 186147997Srwatson if (mtp == NULL) { 187148619Srwatson _memstat_mtl_empty(list); 188147997Srwatson free(buffer); 189148357Srwatson list->mtl_error = MEMSTAT_ERROR_NOMEMORY; 190147997Srwatson return (-1); 191147997Srwatson } 192147997Srwatson 193147997Srwatson /* 194147997Srwatson * Reset the statistics on a current node. 195147997Srwatson */ 196224569Spluknet _memstat_mt_reset_stats(mtp, maxid + 1); 197147997Srwatson 198148007Srwatson mtp->mt_numallocs = uthp->uth_allocs; 199148007Srwatson mtp->mt_numfrees = uthp->uth_frees; 200148071Srwatson mtp->mt_failures = uthp->uth_fails; 201209215Ssbruno mtp->mt_sleeps = uthp->uth_sleeps; 202148007Srwatson 203147997Srwatson for (j = 0; j < maxcpus; j++) { 204147997Srwatson upsp = (struct uma_percpu_stat *)p; 205147997Srwatson p += sizeof(*upsp); 206147997Srwatson 207147997Srwatson mtp->mt_percpu_cache[j].mtp_free = 208147997Srwatson upsp->ups_cache_free; 209147997Srwatson mtp->mt_free += upsp->ups_cache_free; 210147997Srwatson mtp->mt_numallocs += upsp->ups_allocs; 211147997Srwatson mtp->mt_numfrees += upsp->ups_frees; 212147997Srwatson } 213147997Srwatson 214147997Srwatson mtp->mt_size = uthp->uth_size; 215148007Srwatson mtp->mt_memalloced = mtp->mt_numallocs * uthp->uth_size; 216148007Srwatson mtp->mt_memfreed = mtp->mt_numfrees * uthp->uth_size; 217147997Srwatson mtp->mt_bytes = mtp->mt_memalloced - mtp->mt_memfreed; 218147997Srwatson mtp->mt_countlimit = uthp->uth_limit; 219147997Srwatson mtp->mt_byteslimit = uthp->uth_limit * uthp->uth_size; 220147997Srwatson 221147997Srwatson mtp->mt_count = mtp->mt_numallocs - mtp->mt_numfrees; 222148170Srwatson mtp->mt_zonefree = uthp->uth_zone_free; 223148381Srwatson 224148381Srwatson /* 225148381Srwatson * UMA secondary zones share a keg with the primary zone. To 226148381Srwatson * avoid double-reporting of free items, report keg free 227148381Srwatson * items only in the primary zone. 228148381Srwatson */ 229148381Srwatson if (!(uthp->uth_zone_flags & UTH_ZONE_SECONDARY)) { 230148619Srwatson mtp->mt_kegfree = uthp->uth_keg_free; 231148381Srwatson mtp->mt_free += mtp->mt_kegfree; 232148381Srwatson } 233147997Srwatson mtp->mt_free += mtp->mt_zonefree; 234147997Srwatson } 235147997Srwatson 236147997Srwatson free(buffer); 237147997Srwatson 238147997Srwatson return (0); 239147997Srwatson} 240148627Srwatson 241148627Srwatsonstatic int 242148627Srwatsonkread(kvm_t *kvm, void *kvm_pointer, void *address, size_t size, 243148627Srwatson size_t offset) 244148627Srwatson{ 245148627Srwatson ssize_t ret; 246148627Srwatson 247148627Srwatson ret = kvm_read(kvm, (unsigned long)kvm_pointer + offset, address, 248148627Srwatson size); 249148627Srwatson if (ret < 0) 250148627Srwatson return (MEMSTAT_ERROR_KVM); 251148627Srwatson if ((size_t)ret != size) 252148627Srwatson return (MEMSTAT_ERROR_KVM_SHORTREAD); 253148627Srwatson return (0); 254148627Srwatson} 255148627Srwatson 256148627Srwatsonstatic int 257242152Smdfkread_string(kvm_t *kvm, const void *kvm_pointer, char *buffer, int buflen) 258148627Srwatson{ 259148627Srwatson ssize_t ret; 260148627Srwatson int i; 261148627Srwatson 262148627Srwatson for (i = 0; i < buflen; i++) { 263148627Srwatson ret = kvm_read(kvm, (unsigned long)kvm_pointer + i, 264148627Srwatson &(buffer[i]), sizeof(char)); 265148627Srwatson if (ret < 0) 266148627Srwatson return (MEMSTAT_ERROR_KVM); 267148627Srwatson if ((size_t)ret != sizeof(char)) 268148627Srwatson return (MEMSTAT_ERROR_KVM_SHORTREAD); 269148627Srwatson if (buffer[i] == '\0') 270148627Srwatson return (0); 271148627Srwatson } 272148627Srwatson /* Truncate. */ 273148627Srwatson buffer[i-1] = '\0'; 274148627Srwatson return (0); 275148627Srwatson} 276148627Srwatson 277148627Srwatsonstatic int 278148627Srwatsonkread_symbol(kvm_t *kvm, int index, void *address, size_t size, 279148627Srwatson size_t offset) 280148627Srwatson{ 281148627Srwatson ssize_t ret; 282148627Srwatson 283148627Srwatson ret = kvm_read(kvm, namelist[index].n_value + offset, address, size); 284148627Srwatson if (ret < 0) 285148627Srwatson return (MEMSTAT_ERROR_KVM); 286148627Srwatson if ((size_t)ret != size) 287148627Srwatson return (MEMSTAT_ERROR_KVM_SHORTREAD); 288148627Srwatson return (0); 289148627Srwatson} 290148627Srwatson 291148627Srwatson/* 292148627Srwatson * memstat_kvm_uma() is similar to memstat_sysctl_uma(), only it extracts 293148627Srwatson * UMA(9) statistics from a kernel core/memory file. 294148627Srwatson */ 295148627Srwatsonint 296148627Srwatsonmemstat_kvm_uma(struct memory_type_list *list, void *kvm_handle) 297148627Srwatson{ 298154416Srwatson LIST_HEAD(, uma_keg) uma_kegs; 299148627Srwatson struct memory_type *mtp; 300148627Srwatson struct uma_bucket *ubp, ub; 301155550Srwatson struct uma_cache *ucp, *ucp_array; 302148627Srwatson struct uma_zone *uzp, uz; 303148627Srwatson struct uma_keg *kzp, kz; 304148627Srwatson int hint_dontsearch, i, mp_maxid, ret; 305148627Srwatson char name[MEMTYPE_MAXNAME]; 306222813Sattilio cpuset_t all_cpus; 307222813Sattilio long cpusetsize; 308148627Srwatson kvm_t *kvm; 309148627Srwatson 310148627Srwatson kvm = (kvm_t *)kvm_handle; 311148627Srwatson hint_dontsearch = LIST_EMPTY(&list->mtl_list); 312148627Srwatson if (kvm_nlist(kvm, namelist) != 0) { 313148627Srwatson list->mtl_error = MEMSTAT_ERROR_KVM; 314148627Srwatson return (-1); 315148627Srwatson } 316148627Srwatson if (namelist[X_UMA_KEGS].n_type == 0 || 317148627Srwatson namelist[X_UMA_KEGS].n_value == 0) { 318148627Srwatson list->mtl_error = MEMSTAT_ERROR_KVM_NOSYMBOL; 319148627Srwatson return (-1); 320148627Srwatson } 321148627Srwatson ret = kread_symbol(kvm, X_MP_MAXID, &mp_maxid, sizeof(mp_maxid), 0); 322148627Srwatson if (ret != 0) { 323148627Srwatson list->mtl_error = ret; 324148627Srwatson return (-1); 325148627Srwatson } 326148627Srwatson ret = kread_symbol(kvm, X_UMA_KEGS, &uma_kegs, sizeof(uma_kegs), 0); 327148627Srwatson if (ret != 0) { 328148627Srwatson list->mtl_error = ret; 329148627Srwatson return (-1); 330148627Srwatson } 331222813Sattilio cpusetsize = sysconf(_SC_CPUSET_SIZE); 332222813Sattilio if (cpusetsize == -1 || (u_long)cpusetsize > sizeof(cpuset_t)) { 333222813Sattilio list->mtl_error = MEMSTAT_ERROR_KVM_NOSYMBOL; 334222813Sattilio return (-1); 335222813Sattilio } 336222813Sattilio CPU_ZERO(&all_cpus); 337222813Sattilio ret = kread_symbol(kvm, X_ALL_CPUS, &all_cpus, cpusetsize, 0); 338155547Srwatson if (ret != 0) { 339155547Srwatson list->mtl_error = ret; 340155547Srwatson return (-1); 341155547Srwatson } 342155550Srwatson ucp_array = malloc(sizeof(struct uma_cache) * (mp_maxid + 1)); 343155550Srwatson if (ucp_array == NULL) { 344155550Srwatson list->mtl_error = MEMSTAT_ERROR_NOMEMORY; 345155550Srwatson return (-1); 346155550Srwatson } 347148627Srwatson for (kzp = LIST_FIRST(&uma_kegs); kzp != NULL; kzp = 348148627Srwatson LIST_NEXT(&kz, uk_link)) { 349148627Srwatson ret = kread(kvm, kzp, &kz, sizeof(kz), 0); 350148627Srwatson if (ret != 0) { 351155550Srwatson free(ucp_array); 352148627Srwatson _memstat_mtl_empty(list); 353148627Srwatson list->mtl_error = ret; 354148627Srwatson return (-1); 355148627Srwatson } 356148627Srwatson for (uzp = LIST_FIRST(&kz.uk_zones); uzp != NULL; uzp = 357148627Srwatson LIST_NEXT(&uz, uz_link)) { 358148627Srwatson ret = kread(kvm, uzp, &uz, sizeof(uz), 0); 359148627Srwatson if (ret != 0) { 360155550Srwatson free(ucp_array); 361148627Srwatson _memstat_mtl_empty(list); 362148627Srwatson list->mtl_error = ret; 363148627Srwatson return (-1); 364148627Srwatson } 365155550Srwatson ret = kread(kvm, uzp, ucp_array, 366155550Srwatson sizeof(struct uma_cache) * (mp_maxid + 1), 367155550Srwatson offsetof(struct uma_zone, uz_cpu[0])); 368155550Srwatson if (ret != 0) { 369155550Srwatson free(ucp_array); 370155550Srwatson _memstat_mtl_empty(list); 371155550Srwatson list->mtl_error = ret; 372155550Srwatson return (-1); 373155550Srwatson } 374148627Srwatson ret = kread_string(kvm, uz.uz_name, name, 375148627Srwatson MEMTYPE_MAXNAME); 376148627Srwatson if (ret != 0) { 377155550Srwatson free(ucp_array); 378148627Srwatson _memstat_mtl_empty(list); 379148627Srwatson list->mtl_error = ret; 380148627Srwatson return (-1); 381148627Srwatson } 382148627Srwatson if (hint_dontsearch == 0) { 383148627Srwatson mtp = memstat_mtl_find(list, ALLOCATOR_UMA, 384148627Srwatson name); 385148627Srwatson } else 386148627Srwatson mtp = NULL; 387148627Srwatson if (mtp == NULL) 388148627Srwatson mtp = _memstat_mt_allocate(list, ALLOCATOR_UMA, 389224569Spluknet name, mp_maxid + 1); 390148627Srwatson if (mtp == NULL) { 391155550Srwatson free(ucp_array); 392148627Srwatson _memstat_mtl_empty(list); 393148627Srwatson list->mtl_error = MEMSTAT_ERROR_NOMEMORY; 394148627Srwatson return (-1); 395148627Srwatson } 396148627Srwatson /* 397148627Srwatson * Reset the statistics on a current node. 398148627Srwatson */ 399224569Spluknet _memstat_mt_reset_stats(mtp, mp_maxid + 1); 400148627Srwatson mtp->mt_numallocs = uz.uz_allocs; 401148627Srwatson mtp->mt_numfrees = uz.uz_frees; 402148627Srwatson mtp->mt_failures = uz.uz_fails; 403209215Ssbruno mtp->mt_sleeps = uz.uz_sleeps; 404148627Srwatson if (kz.uk_flags & UMA_ZFLAG_INTERNAL) 405148627Srwatson goto skip_percpu; 406148627Srwatson for (i = 0; i < mp_maxid + 1; i++) { 407222813Sattilio if (!CPU_ISSET(i, &all_cpus)) 408155547Srwatson continue; 409155550Srwatson ucp = &ucp_array[i]; 410148627Srwatson mtp->mt_numallocs += ucp->uc_allocs; 411148627Srwatson mtp->mt_numfrees += ucp->uc_frees; 412148627Srwatson 413148627Srwatson if (ucp->uc_allocbucket != NULL) { 414148627Srwatson ret = kread(kvm, ucp->uc_allocbucket, 415148627Srwatson &ub, sizeof(ub), 0); 416148627Srwatson if (ret != 0) { 417155550Srwatson free(ucp_array); 418148627Srwatson _memstat_mtl_empty(list); 419155549Srwatson list->mtl_error = ret; 420148627Srwatson return (-1); 421148627Srwatson } 422148627Srwatson mtp->mt_free += ub.ub_cnt; 423148627Srwatson } 424148627Srwatson if (ucp->uc_freebucket != NULL) { 425148627Srwatson ret = kread(kvm, ucp->uc_freebucket, 426148627Srwatson &ub, sizeof(ub), 0); 427148627Srwatson if (ret != 0) { 428155550Srwatson free(ucp_array); 429148627Srwatson _memstat_mtl_empty(list); 430155549Srwatson list->mtl_error = ret; 431148627Srwatson return (-1); 432148627Srwatson } 433148627Srwatson mtp->mt_free += ub.ub_cnt; 434148627Srwatson } 435148627Srwatson } 436148627Srwatsonskip_percpu: 437148627Srwatson mtp->mt_size = kz.uk_size; 438148627Srwatson mtp->mt_memalloced = mtp->mt_numallocs * mtp->mt_size; 439148627Srwatson mtp->mt_memfreed = mtp->mt_numfrees * mtp->mt_size; 440155542Srwatson mtp->mt_bytes = mtp->mt_memalloced - mtp->mt_memfreed; 441148627Srwatson if (kz.uk_ppera > 1) 442148627Srwatson mtp->mt_countlimit = kz.uk_maxpages / 443148627Srwatson kz.uk_ipers; 444148627Srwatson else 445148627Srwatson mtp->mt_countlimit = kz.uk_maxpages * 446148627Srwatson kz.uk_ipers; 447148627Srwatson mtp->mt_byteslimit = mtp->mt_countlimit * mtp->mt_size; 448148627Srwatson mtp->mt_count = mtp->mt_numallocs - mtp->mt_numfrees; 449251894Sjeff for (ubp = LIST_FIRST(&uz.uz_buckets); ubp != 450148627Srwatson NULL; ubp = LIST_NEXT(&ub, ub_link)) { 451148627Srwatson ret = kread(kvm, ubp, &ub, sizeof(ub), 0); 452148627Srwatson mtp->mt_zonefree += ub.ub_cnt; 453148627Srwatson } 454148627Srwatson if (!((kz.uk_flags & UMA_ZONE_SECONDARY) && 455148627Srwatson LIST_FIRST(&kz.uk_zones) != uzp)) { 456148627Srwatson mtp->mt_kegfree = kz.uk_free; 457148627Srwatson mtp->mt_free += mtp->mt_kegfree; 458148627Srwatson } 459148627Srwatson mtp->mt_free += mtp->mt_zonefree; 460148627Srwatson } 461148627Srwatson } 462155550Srwatson free(ucp_array); 463148627Srwatson return (0); 464148627Srwatson} 465