mirror of
https://git.FreeBSD.org/src.git
synced 2025-02-02 17:08:56 +00:00
Teach umastat about the variable-length array of per-CPU caches at the end
of struct uma_zone. It is declared as an array of size [1], but then sized at run-time by UMA to include room for mp_maxid+1 CPUs. We have to copy the uma_zone first at the declared structure size, then check to make sure it's not an internal zone before copying the larger size (UMA internal zones don't use per-CPU caches). This fixes umastat for SMP.
This commit is contained in:
parent
d5269a636b
commit
eefe20fef7
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=153233
@ -42,11 +42,13 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
static struct nlist namelist[] = {
|
||||
#define X_UMA_KEGS 0
|
||||
#define X_UMA_KEGS 0
|
||||
{ .n_name = "_uma_kegs" },
|
||||
#define X_MP_MAXID 1
|
||||
#define X_MP_MAXCPUS 1
|
||||
{ .n_name = "_mp_maxcpus" },
|
||||
#define X_MP_MAXID 2
|
||||
{ .n_name = "_mp_maxid" },
|
||||
#define X_ALLCPU 2
|
||||
#define X_ALLCPU 3
|
||||
{ .n_name = "_all_cpus" },
|
||||
{ .n_name = "" },
|
||||
};
|
||||
@ -269,9 +271,10 @@ main(int argc, char *argv[])
|
||||
LIST_HEAD(, uma_keg) uma_kegs;
|
||||
char name[MEMTYPE_MAXNAME];
|
||||
struct uma_keg *kzp, kz;
|
||||
struct uma_zone *uzp, uz;
|
||||
struct uma_zone *uzp, *uzp_userspace;
|
||||
kvm_t *kvm;
|
||||
int all_cpus, cpu, mp_maxid, ret;
|
||||
int all_cpus, cpu, mp_maxcpus, mp_maxid, ret;
|
||||
size_t uzp_userspace_len;
|
||||
|
||||
if (argc != 1)
|
||||
usage();
|
||||
@ -287,6 +290,13 @@ main(int argc, char *argv[])
|
||||
namelist[X_UMA_KEGS].n_value == 0)
|
||||
errx(-1, "kvm_nlist return");
|
||||
|
||||
ret = kread_symbol(kvm, X_MP_MAXCPUS, &mp_maxcpus, sizeof(mp_maxcpus),
|
||||
0);
|
||||
if (ret != 0)
|
||||
errx(-1, "kread_symbol: %s", kvm_geterr(kvm));
|
||||
|
||||
printf("mp_maxcpus = %d\n", mp_maxcpus);
|
||||
|
||||
ret = kread_symbol(kvm, X_MP_MAXID, &mp_maxid, sizeof(mp_maxid), 0);
|
||||
if (ret != 0)
|
||||
errx(-1, "kread_symbol: %s", kvm_geterr(kvm));
|
||||
@ -303,11 +313,24 @@ main(int argc, char *argv[])
|
||||
if (ret != 0)
|
||||
errx(-1, "kread_symbol: %s", kvm_geterr(kvm));
|
||||
|
||||
/*
|
||||
* uma_zone_t ends in an array of mp_maxid cache entries. However,
|
||||
* it is statically declared as an array of size 1, so we need to
|
||||
* provide additional space.
|
||||
*/
|
||||
uzp_userspace_len = sizeof(struct uma_zone) + (mp_maxid - 1) *
|
||||
sizeof(struct uma_cache);
|
||||
uzp_userspace = malloc(uzp_userspace_len);
|
||||
if (uzp_userspace == NULL)
|
||||
err(-1, "malloc");
|
||||
|
||||
for (kzp = LIST_FIRST(&uma_kegs); kzp != NULL; kzp =
|
||||
LIST_NEXT(&kz, uk_link)) {
|
||||
ret = kread(kvm, kzp, &kz, sizeof(kz), 0);
|
||||
if (ret != 0)
|
||||
if (ret != 0) {
|
||||
free(uzp_userspace);
|
||||
errx(-1, "kread: %s", kvm_geterr(kvm));
|
||||
}
|
||||
printf("Keg {\n");
|
||||
|
||||
printf(" uk_recurse = %d\n", kz.uk_recurse);
|
||||
@ -329,34 +352,61 @@ main(int argc, char *argv[])
|
||||
continue;
|
||||
}
|
||||
for (uzp = LIST_FIRST(&kz.uk_zones); uzp != NULL; uzp =
|
||||
LIST_NEXT(&uz, uz_link)) {
|
||||
ret = kread(kvm, uzp, &uz, sizeof(uz), 0);
|
||||
if (ret != 0)
|
||||
LIST_NEXT(uzp_userspace, uz_link)) {
|
||||
/*
|
||||
* We actually copy in twice: once with the base
|
||||
* structure, so that we can then decide if we also
|
||||
* need to copy in the caches. This prevents us
|
||||
* from reading past the end of the base UMA zones,
|
||||
* which is unlikely to cause problems but could.
|
||||
*/
|
||||
ret = kread(kvm, uzp, uzp_userspace,
|
||||
sizeof(struct uma_zone), 0);
|
||||
if (ret != 0) {
|
||||
free(uzp_userspace);
|
||||
errx(-1, "kread: %s", kvm_geterr(kvm));
|
||||
ret = kread_string(kvm, uz.uz_name, name,
|
||||
}
|
||||
if (!(kz.uk_flags & UMA_ZFLAG_INTERNAL)) {
|
||||
ret = kread(kvm, uzp, uzp_userspace,
|
||||
uzp_userspace_len, 0);
|
||||
if (ret != 0) {
|
||||
free(uzp_userspace);
|
||||
errx(-1, "kread: %s",
|
||||
kvm_geterr(kvm));
|
||||
}
|
||||
}
|
||||
ret = kread_string(kvm, uzp_userspace->uz_name, name,
|
||||
MEMTYPE_MAXNAME);
|
||||
if (ret != 0)
|
||||
if (ret != 0) {
|
||||
free(uzp_userspace);
|
||||
errx(-1, "kread_string: %s", kvm_geterr(kvm));
|
||||
}
|
||||
printf(" Zone {\n");
|
||||
printf(" uz_name = \"%s\";\n", name);
|
||||
printf(" uz_allocs = %llu;\n", uz.uz_allocs);
|
||||
printf(" uz_frees = %llu;\n", uz.uz_frees);
|
||||
printf(" uz_fails = %llu;\n", uz.uz_fails);
|
||||
printf(" uz_fills = %u;\n", uz.uz_fills);
|
||||
printf(" uz_count = %u;\n", uz.uz_count);
|
||||
uma_print_bucketlist(kvm,
|
||||
(struct bucketlist *)&uz.uz_full_bucket,
|
||||
"uz_full_bucket", " ");
|
||||
uma_print_bucketlist(kvm,
|
||||
(struct bucketlist *)&uz.uz_free_bucket,
|
||||
"uz_free_bucket", " ");
|
||||
printf(" uz_allocs = %llu;\n",
|
||||
uzp_userspace->uz_allocs);
|
||||
printf(" uz_frees = %llu;\n",
|
||||
uzp_userspace->uz_frees);
|
||||
printf(" uz_fails = %llu;\n",
|
||||
uzp_userspace->uz_fails);
|
||||
printf(" uz_fills = %u;\n",
|
||||
uzp_userspace->uz_fills);
|
||||
printf(" uz_count = %u;\n",
|
||||
uzp_userspace->uz_count);
|
||||
uma_print_bucketlist(kvm, (struct bucketlist *)
|
||||
&uzp_userspace->uz_full_bucket, "uz_full_bucket",
|
||||
" ");
|
||||
uma_print_bucketlist(kvm, (struct bucketlist *)
|
||||
&uzp_userspace->uz_free_bucket, "uz_free_bucket",
|
||||
" ");
|
||||
|
||||
if (!(kz.uk_flags & UMA_ZFLAG_INTERNAL)) {
|
||||
for (cpu = 0; cpu < mp_maxid; cpu++) {
|
||||
/* if (CPU_ABSENT(cpu)) */
|
||||
if ((all_cpus & (1 << cpu)) == 0)
|
||||
continue;
|
||||
uma_print_cache(kvm, &uz.uz_cpu[cpu],
|
||||
uma_print_cache(kvm,
|
||||
&uzp_userspace->uz_cpu[cpu],
|
||||
"uc_cache", cpu, " ");
|
||||
}
|
||||
}
|
||||
@ -366,5 +416,6 @@ main(int argc, char *argv[])
|
||||
printf("};\n");
|
||||
}
|
||||
|
||||
free(uzp_userspace);
|
||||
return (0);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user