Modify netstat -mb to use libmemstat when accessing a core dump or live

kernel memory and not using sysctl.  Previously, libmemstat was used
only for the live kernel via sysctl paths.

This results in netstat output becoming both more consistent between
core dumps and the live kernel, and also more information in the core
dump case than previously (i.e., mbuf cache information).

Statistics relating to sfbufs still rely on a kvm descriptor as they
are not currently exposed via libmemstat.  netstat -m operating on a
core is still unable to print certain sfbuf stats available on the live
kernel.

MFC after:	1 week
This commit is contained in:
Robert Watson 2005-11-13 14:06:01 +00:00
parent be2cb7fae9
commit d4426f281d
3 changed files with 54 additions and 178 deletions

View File

@ -447,19 +447,9 @@ main(int argc, char *argv[])
if (mflag) {
if (memf != NULL) {
if (kread(0, 0, 0) == 0)
mbpr(nl[N_MBSTAT].n_value,
nl[N_MBTYPES].n_value,
nl[N_NMBCLUSTERS].n_value,
nl[N_NMBUFS].n_value,
nl[N_MBHI].n_value,
nl[N_CLHI].n_value,
nl[N_MBLO].n_value,
nl[N_CLLO].n_value,
nl[N_NCPUS].n_value,
nl[N_PAGESZ].n_value,
nl[N_MBPSTAT].n_value);
mbpr(kvmd, nl[N_MBSTAT].n_value);
} else
mbpr(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
mbpr(NULL, 0);
exit(0);
}
#if 0

View File

@ -49,138 +49,18 @@ __FBSDID("$FreeBSD$");
#include <sys/sysctl.h>
#include <err.h>
#include <kvm.h>
#include <memstat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "netstat.h"
#define YES 1
typedef int bool;
static struct mbtypenames {
short mt_type;
const char *mt_name;
} mbtypenames[] = {
{ MT_DATA, "data" },
{ MT_OOBDATA, "oob data" },
{ MT_CONTROL, "ancillary data" },
{ MT_HEADER, "packet headers" },
#ifdef MT_SOCKET
{ MT_SOCKET, "socket structures" }, /* XXX */
#endif
#ifdef MT_PCB
{ MT_PCB, "protocol control blocks" }, /* XXX */
#endif
#ifdef MT_RTABLE
{ MT_RTABLE, "routing table entries" }, /* XXX */
#endif
#ifdef MT_HTABLE
{ MT_HTABLE, "IMP host table entries" }, /* XXX */
#endif
#ifdef MT_ATABLE
{ MT_ATABLE, "address resolution tables" },
#endif
{ MT_FTABLE, "fragment reassembly queue headers" }, /* XXX */
{ MT_SONAME, "socket names and addresses" },
#ifdef MT_SOOPTS
{ MT_SOOPTS, "socket options" },
#endif
#ifdef MT_RIGHTS
{ MT_RIGHTS, "access rights" },
#endif
#ifdef MT_IFADDR
{ MT_IFADDR, "interface addresses" }, /* XXX */
#endif
{ 0, 0 }
};
/*
* Print mbuf statistics extracted from kmem.
* Print mbuf statistics.
*/
void
mbpr_kmem(u_long mbaddr, u_long nmbcaddr, u_long nmbufaddr, u_long mbhiaddr,
u_long clhiaddr, u_long mbloaddr, u_long clloaddr, u_long pgsaddr,
u_long mbpaddr)
{
int i, nmbclusters;
short nmbtypes;
size_t mlen;
long *mbtypes = NULL;
struct mbstat *mbstat = NULL;
struct mbtypenames *mp;
bool *seen = NULL;
mlen = sizeof *mbstat;
if ((mbstat = malloc(mlen)) == NULL) {
warn("malloc: cannot allocate memory for mbstat");
goto err;
}
if (kread(mbaddr, (char *)mbstat, sizeof mbstat))
goto err;
if (kread(nmbcaddr, (char *)&nmbclusters, sizeof(int)))
goto err;
if (mbstat->m_mbufs < 0) mbstat->m_mbufs = 0; /* XXX */
if (mbstat->m_mclusts < 0) mbstat->m_mclusts = 0; /* XXX */
nmbtypes = mbstat->m_numtypes;
if ((seen = calloc(nmbtypes, sizeof(*seen))) == NULL) {
warn("calloc: cannot allocate memory for mbtypes seen flag");
goto err;
}
if ((mbtypes = calloc(nmbtypes, sizeof(long *))) == NULL) {
warn("calloc: cannot allocate memory for mbtypes");
goto err;
}
#undef MSIZE
#define MSIZE (mbstat->m_msize)
#undef MCLBYTES
#define MCLBYTES (mbstat->m_mclbytes)
printf("%lu mbufs in use\n", mbstat->m_mbufs);
for (mp = mbtypenames; mp->mt_name; mp++) {
if (mbtypes[mp->mt_type]) {
seen[mp->mt_type] = YES;
printf("\t %lu mbufs allocated to %s\n",
mbtypes[mp->mt_type], mp->mt_name);
}
}
for (i = 1; i < nmbtypes; i++) {
if (!seen[i] && mbtypes[i])
printf("\t %lu mbufs allocated to <mbuf type: %d>\n",
mbtypes[i], i);
}
printf("%lu/%d mbuf clusters in use (current/max)\n",
mbstat->m_mclusts, nmbclusters);
printf("%lu KBytes allocated to network\n", (mbstat->m_mbufs * MSIZE +
mbstat->m_mclusts * MCLBYTES) / 1024);
printf("%lu requests for sfbufs denied\n", mbstat->sf_allocfail);
printf("%lu requests for sfbufs delayed\n", mbstat->sf_allocwait);
printf("%lu requests for I/O initiated by sendfile\n",
mbstat->sf_iocnt);
printf("%lu calls to protocol drain routines\n", mbstat->m_drain);
err:
if (mbtypes != NULL)
free(mbtypes);
if (seen != NULL)
free(seen);
if (mbstat != NULL)
free(mbstat);
}
/*
* If running on a live kernel, directly query the zone allocator for stats
* from the four mbuf-related zones/types.
*/
static void
mbpr_sysctl(void)
mbpr(void *kvmd, u_long mbaddr)
{
struct memory_type_list *mtlp;
struct memory_type *mtp;
@ -193,7 +73,9 @@ mbpr_sysctl(void)
int nsfbufs, nsfbufspeak, nsfbufsused;
struct mbstat mbstat;
size_t mlen;
int error, live;
live = (kvmd == NULL);
mtlp = memstat_mtl_alloc();
if (mtlp == NULL) {
warn("memstat_mtl_alloc");
@ -201,14 +83,29 @@ mbpr_sysctl(void)
}
/*
* Use memstat_sysctl_all() because some mbuf-related memory is in
* uma(9), and some malloc(9).
* Use memstat_*_all() because some mbuf-related memory is in uma(9),
* and some malloc(9).
*/
if (live) {
printf("live\n");
if (memstat_sysctl_all(mtlp, 0) < 0) {
warnx("memstat_sysctl_all: %s",
memstat_strerror(memstat_mtl_geterror(mtlp)));
goto out;
}
} else {
printf("kvm\n");
if (memstat_kvm_all(mtlp, kvmd) < 0) {
error = memstat_mtl_geterror(mtlp);
if (error == MEMSTAT_ERROR_KVM)
warnx("memstat_kvm_all: %s",
kvm_geterr(kvmd));
else
warnx("memstat_kvm_all: %s",
memstat_strerror(error));
goto out;
}
}
mtp = memstat_mtl_find(mtlp, ALLOCATOR_UMA, MBUF_MEM_NAME);
if (mtp == NULL) {
@ -267,15 +164,18 @@ mbpr_sysctl(void)
printf("%llu mbuf tags in use\n", tag_count);
#endif
if (live) {
mlen = sizeof(nsfbufs);
if (!sysctlbyname("kern.ipc.nsfbufs", &nsfbufs, &mlen, NULL, 0) &&
!sysctlbyname("kern.ipc.nsfbufsused", &nsfbufsused, &mlen, NULL,
if (!sysctlbyname("kern.ipc.nsfbufs", &nsfbufs, &mlen, NULL,
0) &&
!sysctlbyname("kern.ipc.nsfbufspeak", &nsfbufspeak, &mlen, NULL,
0)) {
!sysctlbyname("kern.ipc.nsfbufsused", &nsfbufsused,
&mlen, NULL, 0) &&
!sysctlbyname("kern.ipc.nsfbufspeak", &nsfbufspeak,
&mlen, NULL, 0)) {
printf("%d/%d/%d sfbufs in use (current/peak/max)\n",
nsfbufsused, nsfbufspeak, nsfbufs);
}
}
/*-
* Calculate in-use bytes as:
@ -326,34 +226,21 @@ mbpr_sysctl(void)
packet_failures);
#endif
if (live) {
mlen = sizeof(mbstat);
if (!sysctlbyname("kern.ipc.mbstat", &mbstat, &mlen, NULL, 0)) {
printf("%lu requests for sfbufs denied\n",
mbstat.sf_allocfail);
printf("%lu requests for sfbufs delayed\n",
mbstat.sf_allocwait);
if (sysctlbyname("kern.ipc.mbstat", &mbstat, &mlen, NULL, 0)) {
warn("kern.ipc.mbstat");
goto out;
}
} else {
if (kread(mbaddr, (char *)&mbstat, sizeof mbstat))
goto out;
}
printf("%lu requests for sfbufs denied\n", mbstat.sf_allocfail);
printf("%lu requests for sfbufs delayed\n", mbstat.sf_allocwait);
printf("%lu requests for I/O initiated by sendfile\n",
mbstat.sf_iocnt);
printf("%lu calls to protocol drain routines\n",
mbstat.m_drain);
}
printf("%lu calls to protocol drain routines\n", mbstat.m_drain);
out:
memstat_mtl_free(mtlp);
}
/*
* Print mbuf statistics.
*/
void
mbpr(u_long mbaddr, u_long mbtaddr __unused, u_long nmbcaddr, u_long nmbufaddr,
u_long mbhiaddr, u_long clhiaddr, u_long mbloaddr, u_long clloaddr,
u_long cpusaddr __unused, u_long pgsaddr, u_long mbpaddr)
{
if (mbaddr != 0)
mbpr_kmem(mbaddr, nmbcaddr, nmbufaddr, mbhiaddr, clhiaddr,
mbloaddr, clloaddr, pgsaddr, mbpaddr);
else
mbpr_sysctl();
}

View File

@ -99,8 +99,7 @@ void inet6print(struct in6_addr *, int, const char *, int);
void pfkey_stats(u_long, const char *, int);
#endif
void mbpr(u_long, u_long, u_long, u_long, u_long, u_long,
u_long, u_long, u_long, u_long, u_long);
void mbpr(void *, u_long);
void hostpr(u_long, u_long);
void impstats(u_long, u_long);