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