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