Add an mbuf provider to DTrace.
The mbuf provider is made up of a set of Statically Defined Tracepoints which help us look into mbufs as they are allocated and freed. This can be used to inspect the buffers or for a simplified mbuf leak detector. New tracepoints are: mbuf:::m-init mbuf:::m-gethdr mbuf:::m-get mbuf:::m-getcl mbuf:::m-clget mbuf:::m-cljget mbuf:::m-cljset mbuf:::m-free mbuf:::m-freem There is also a translator for mbufs which gives some visibility into the structure, see mbuf.d for more details. Reviewed by: bz, markj MFC after: 2 weeks Sponsored by: Rubicon Communications (Netgate) Differential Revision: https://reviews.freebsd.org/D5682
This commit is contained in:
parent
6b2ac2319d
commit
e4786b4992
@ -30,4 +30,10 @@ SCRIPTS= blocking \
|
||||
|
||||
SCRIPTSDIR= ${SHAREDIR}/dtrace
|
||||
|
||||
DSRCS= mbuf.d
|
||||
|
||||
FILES= ${DSRCS}
|
||||
FILESDIR= /usr/lib/dtrace
|
||||
FILESMODE= ${NOBINMODE}
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
211
share/dtrace/mbuf.d
Normal file
211
share/dtrace/mbuf.d
Normal file
@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright (c) 2016 George V. Neville-Neil
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*
|
||||
* Translators and flags for the mbuf structure. FreeBSD specific code.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma D depends_on module kernel
|
||||
#pragma D depends_on provider mbuf
|
||||
|
||||
/*
|
||||
* mbuf flags of global significance and layer crossing.
|
||||
* Those of only protocol/layer specific significance are to be mapped
|
||||
* to M_PROTO[1-12] and cleared at layer handoff boundaries.
|
||||
* NB: Limited to the lower 24 bits.
|
||||
*/
|
||||
|
||||
#pragma D binding "1.6.3" M_EXT
|
||||
inline int M_EXT = 0x00000001; /* has associated external storage */
|
||||
#pragma D binding "1.6.3" M_PKTHDR
|
||||
inline int M_PKTHDR = 0x00000002; /* start of record */
|
||||
#pragma D binding "1.6.3" M_EOR
|
||||
inline int M_EOR = 0x00000004; /* end of record */
|
||||
#pragma D binding "1.6.3" M_RDONLY
|
||||
inline int M_RDONLY = 0x00000008; /* associated data is marked read-only */
|
||||
#pragma D binding "1.6.3" M_BCAST
|
||||
inline int M_BCAST = 0x00000010; /* send/received as link-level broadcast */
|
||||
#pragma D binding "1.6.3" M_MCAST
|
||||
inline int M_MCAST = 0x00000020; /* send/received as link-level multicast */
|
||||
#pragma D binding "1.6.3" M_PROMISC
|
||||
inline int M_PROMISC = 0x00000040; /* packet was not for us */
|
||||
#pragma D binding "1.6.3" M_VLANTAG
|
||||
inline int M_VLANTAG = 0x00000080; /* ether_vtag is valid */
|
||||
#pragma D binding "1.6.3" M_UNUSED_8
|
||||
inline int M_UNUSED_8 = 0x00000100; /* --available-- */
|
||||
#pragma D binding "1.6.3" M_NOFREE
|
||||
inline int M_NOFREE = 0x00000200; /* do not free mbuf, embedded in cluster */
|
||||
|
||||
#pragma D binding "1.6.3" M_PROTO1
|
||||
inline int M_PROTO1 = 0x00001000; /* protocol-specific */
|
||||
#pragma D binding "1.6.3" M_PROTO2
|
||||
inline int M_PROTO2 = 0x00002000; /* protocol-specific */
|
||||
#pragma D binding "1.6.3" M_PROTO3
|
||||
inline int M_PROTO3 = 0x00004000; /* protocol-specific */
|
||||
#pragma D binding "1.6.3" M_PROTO4
|
||||
inline int M_PROTO4 = 0x00008000; /* protocol-specific */
|
||||
#pragma D binding "1.6.3" M_PROTO5
|
||||
inline int M_PROTO5 = 0x00010000; /* protocol-specific */
|
||||
#pragma D binding "1.6.3" M_PROTO6
|
||||
inline int M_PROTO6 = 0x00020000; /* protocol-specific */
|
||||
#pragma D binding "1.6.3" M_PROTO7
|
||||
inline int M_PROTO7 = 0x00040000; /* protocol-specific */
|
||||
#pragma D binding "1.6.3" M_PROTO8
|
||||
inline int M_PROTO8 = 0x00080000; /* protocol-specific */
|
||||
#pragma D binding "1.6.3" M_PROTO9
|
||||
inline int M_PROTO9 = 0x00100000; /* protocol-specific */
|
||||
#pragma D binding "1.6.3" M_PROTO10
|
||||
inline int M_PROTO10 = 0x00200000; /* protocol-specific */
|
||||
#pragma D binding "1.6.3" M_PROTO11
|
||||
inline int M_PROTO11 = 0x00400000; /* protocol-specific */
|
||||
#pragma D binding "1.6.3" M_PROTO12
|
||||
inline int M_PROTO12 = 0x00800000; /* protocol-specific */
|
||||
|
||||
#pragma D binding "1.6.3" mbufflags_string
|
||||
inline string mbufflags_string[uint32_t flags] =
|
||||
flags & M_EXT ? "M_EXT" :
|
||||
flags & M_PKTHDR ? "M_PKTHDR" :
|
||||
flags & M_EOR ? "M_EOR" :
|
||||
flags & M_RDONLY ? "M_RDONLY" :
|
||||
flags & M_BCAST ? "M_BCAST" :
|
||||
flags & M_MCAST ? "M_MCAST" :
|
||||
flags & M_PROMISC ? "M_PROMISC" :
|
||||
flags & M_VLANTAG ? "M_VLANTAG" :
|
||||
flags & M_UNUSED_8 ? "M_UNUSED_8" :
|
||||
flags & M_NOFREE ? "M_NOFREE" :
|
||||
flags & M_PROTO1 ? "M_PROTO1" :
|
||||
flags & M_PROTO2 ? "M_PROTO2" :
|
||||
flags & M_PROTO3 ? "M_PROTO3" :
|
||||
flags & M_PROTO4 ? "M_PROTO4" :
|
||||
flags & M_PROTO5 ? "M_PROTO5" :
|
||||
flags & M_PROTO6 ? "M_PROTO6" :
|
||||
flags & M_PROTO7 ? "M_PROTO7" :
|
||||
flags & M_PROTO8 ? "M_PROTO8" :
|
||||
flags & M_PROTO9 ? "M_PROTO9" :
|
||||
flags & M_PROTO10 ? "M_PROTO10" :
|
||||
flags & M_PROTO11 ? "M_PROTO11" :
|
||||
flags & M_PROTO12 ? "M_PROTO12" :
|
||||
"none" ;
|
||||
|
||||
/*
|
||||
* Packet tag structure (see below for details).
|
||||
*/
|
||||
typedef struct m_tag {
|
||||
u_int16_t m_tag_id; /* Tag ID */
|
||||
u_int16_t m_tag_len; /* Length of data */
|
||||
u_int32_t m_tag_cookie; /* ABI/Module ID */
|
||||
} m_tag_t;
|
||||
|
||||
/*
|
||||
* Record/packet header in first mbuf of chain; valid only if M_PKTHDR is set.
|
||||
* Size ILP32: 48
|
||||
* LP64: 56
|
||||
* Compile-time assertions in uipc_mbuf.c test these values to ensure that
|
||||
* they are correct.
|
||||
*/
|
||||
typedef struct pkthdr {
|
||||
/* struct ifnet *rcvif; */ /* rcv interface */
|
||||
int32_t len; /* total packet length */
|
||||
|
||||
/* Layer crossing persistent information. */
|
||||
uint32_t flowid; /* packet's 4-tuple system */
|
||||
uint64_t csum_flags; /* checksum and offload features */
|
||||
uint16_t fibnum; /* this packet should use this fib */
|
||||
uint8_t cosqos; /* class/quality of service */
|
||||
uint8_t rsstype; /* hash type */
|
||||
} pkthdr_t;
|
||||
|
||||
/*
|
||||
* Description of external storage mapped into mbuf; valid only if M_EXT is
|
||||
* set.
|
||||
* Size ILP32: 28
|
||||
* LP64: 48
|
||||
* Compile-time assertions in uipc_mbuf.c test these values to ensure that
|
||||
* they are correct.
|
||||
*/
|
||||
typedef struct m_ext {
|
||||
volatile u_int *ext_cnt; /* pointer to ref count info */
|
||||
caddr_t ext_buf; /* start of buffer */
|
||||
uint32_t ext_size; /* size of buffer, for ext_free */
|
||||
uint32_t ext_type:8, /* type of external storage */
|
||||
ext_flags:24; /* external storage mbuf flags */
|
||||
void *ext_arg1; /* optional argument pointer */
|
||||
void *ext_arg2; /* optional argument pointer */
|
||||
} m_ext_t;
|
||||
|
||||
/*
|
||||
* The core of the mbuf object along with some shortcut defines for practical
|
||||
* purposes.
|
||||
*/
|
||||
struct mbuf {
|
||||
uintptr_t mbuf_addr;
|
||||
/*
|
||||
* Header present at the beginning of every mbuf.
|
||||
* Size ILP32: 24
|
||||
* LP64: 32
|
||||
* Compile-time assertions in uipc_mbuf.c test these values to ensure
|
||||
* that they are correct.
|
||||
*/
|
||||
caddr_t m_data; /* location of data */
|
||||
int32_t m_len; /* amount of data in this mbuf */
|
||||
uint32_t m_type:8, /* type of data in this mbuf */
|
||||
m_flags:24; /* flags; see below */
|
||||
/*
|
||||
* A set of optional headers (packet header, external storage header)
|
||||
* and internal data storage. Historically, these arrays were sized
|
||||
* to MHLEN (space left after a packet header) and MLEN (space left
|
||||
* after only a regular mbuf header); they are now variable size in
|
||||
* order to support future work on variable-size mbufs.
|
||||
*/
|
||||
/* union { */
|
||||
/* struct { */
|
||||
/* struct pkthdr m_pkthdr; */
|
||||
/* union { */
|
||||
/* struct m_ext m_ext; */
|
||||
/* char m_pktdat[0]; */
|
||||
/* }; */
|
||||
/* }; */
|
||||
/* char m_dat[0]; */
|
||||
/* }; */
|
||||
char *m_dat;
|
||||
};
|
||||
|
||||
typedef struct mbufinfo {
|
||||
uintptr_t mbuf_addr;
|
||||
caddr_t m_data;
|
||||
int32_t m_len;
|
||||
uint8_t m_type;
|
||||
uint32_t m_flags;
|
||||
} mbufinfo_t;
|
||||
|
||||
translator mbufinfo_t < struct mbuf *p > {
|
||||
mbuf_addr = (uintptr_t)p;
|
||||
m_data = p->m_data;
|
||||
m_len = p->m_len;
|
||||
m_type = p->m_type & 0xff000000;
|
||||
m_flags = p->m_type & 0x00ffffff;
|
||||
};
|
@ -731,6 +731,7 @@ m_clget(struct mbuf *m, int how)
|
||||
zone_drain(zone_pack);
|
||||
uma_zalloc_arg(zone_clust, m, how);
|
||||
}
|
||||
MBUF_PROBE2(m__clget, m, how);
|
||||
return (m->m_flags & M_EXT);
|
||||
}
|
||||
|
||||
@ -745,7 +746,8 @@ void *
|
||||
m_cljget(struct mbuf *m, int how, int size)
|
||||
{
|
||||
uma_zone_t zone;
|
||||
|
||||
void *retval;
|
||||
|
||||
if (m != NULL) {
|
||||
KASSERT((m->m_flags & M_EXT) == 0, ("%s: mbuf %p has M_EXT",
|
||||
__func__, m));
|
||||
@ -753,7 +755,11 @@ m_cljget(struct mbuf *m, int how, int size)
|
||||
}
|
||||
|
||||
zone = m_getzone(size);
|
||||
return (uma_zalloc_arg(zone, m, how));
|
||||
retval = uma_zalloc_arg(zone, m, how);
|
||||
|
||||
MBUF_PROBE4(m__cljget, m, how, size, retval);
|
||||
|
||||
return (retval);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -933,6 +939,7 @@ m_extadd(struct mbuf *mb, caddr_t buf, u_int size,
|
||||
void
|
||||
m_freem(struct mbuf *mb)
|
||||
{
|
||||
MBUF_PROBE1(m__freem, mb);
|
||||
|
||||
while (mb != NULL)
|
||||
mb = m_free(mb);
|
||||
|
@ -47,6 +47,51 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/domain.h>
|
||||
#include <sys/protosw.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/sdt.h>
|
||||
|
||||
SDT_PROVIDER_DEFINE(mbuf);
|
||||
|
||||
SDT_PROBE_DEFINE5_XLATE(mbuf, , , m__init,
|
||||
"struct mbuf *", "mbufinfo_t *",
|
||||
"uint32_t", "uint32_t",
|
||||
"uint16_t", "uint16_t",
|
||||
"uint32_t", "uint32_t",
|
||||
"uint32_t", "uint32_t");
|
||||
|
||||
SDT_PROBE_DEFINE3_XLATE(mbuf, , , m__gethdr,
|
||||
"uint32_t", "uint32_t",
|
||||
"uint16_t", "uint16_t",
|
||||
"struct mbuf *", "mbufinfo_t *");
|
||||
|
||||
SDT_PROBE_DEFINE3_XLATE(mbuf, , , m__get,
|
||||
"uint32_t", "uint32_t",
|
||||
"uint16_t", "uint16_t",
|
||||
"struct mbuf *", "mbufinfo_t *");
|
||||
|
||||
SDT_PROBE_DEFINE4_XLATE(mbuf, , , m__getcl,
|
||||
"uint32_t", "uint32_t",
|
||||
"uint16_t", "uint16_t",
|
||||
"uint32_t", "uint32_t",
|
||||
"struct mbuf *", "mbufinfo_t *");
|
||||
|
||||
SDT_PROBE_DEFINE3_XLATE(mbuf, , , m__clget,
|
||||
"struct mbuf *", "mbufinfo_t *",
|
||||
"uint32_t", "uint32_t",
|
||||
"uint32_t", "uint32_t");
|
||||
|
||||
SDT_PROBE_DEFINE4_XLATE(mbuf, , , m__cljget,
|
||||
"struct mbuf *", "mbufinfo_t *",
|
||||
"uint32_t", "uint32_t",
|
||||
"uint32_t", "uint32_t",
|
||||
"void*", "void*");
|
||||
|
||||
SDT_PROBE_DEFINE(mbuf, , , m__cljset);
|
||||
|
||||
SDT_PROBE_DEFINE1_XLATE(mbuf, , , m__free,
|
||||
"struct mbuf *", "mbufinfo_t *");
|
||||
|
||||
SDT_PROBE_DEFINE1_XLATE(mbuf, , , m__freem,
|
||||
"struct mbuf *", "mbufinfo_t *");
|
||||
|
||||
#include <security/mac/mac_framework.h>
|
||||
|
||||
|
@ -44,6 +44,34 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include <sys/sdt.h>
|
||||
|
||||
#define MBUF_PROBE1(probe, arg0) \
|
||||
SDT_PROBE1(mbuf, , , probe, arg0)
|
||||
#define MBUF_PROBE2(probe, arg0, arg1) \
|
||||
SDT_PROBE2(mbuf, , , probe, arg0, arg1)
|
||||
#define MBUF_PROBE3(probe, arg0, arg1, arg2) \
|
||||
SDT_PROBE3(mbuf, , , probe, arg0, arg1, arg2)
|
||||
#define MBUF_PROBE4(probe, arg0, arg1, arg2, arg3) \
|
||||
SDT_PROBE4(mbuf, , , probe, arg0, arg1, arg2, arg3)
|
||||
#define MBUF_PROBE5(probe, arg0, arg1, arg2, arg3, arg4) \
|
||||
SDT_PROBE5(mbuf, , , probe, arg0, arg1, arg2, arg3, arg4)
|
||||
|
||||
SDT_PROVIDER_DECLARE(mbuf);
|
||||
|
||||
SDT_PROBE_DECLARE(mbuf, , , m__init);
|
||||
SDT_PROBE_DECLARE(mbuf, , , m__gethdr);
|
||||
SDT_PROBE_DECLARE(mbuf, , , m__get);
|
||||
SDT_PROBE_DECLARE(mbuf, , , m__getcl);
|
||||
SDT_PROBE_DECLARE(mbuf, , , m__clget);
|
||||
SDT_PROBE_DECLARE(mbuf, , , m__cljget);
|
||||
SDT_PROBE_DECLARE(mbuf, , , m__cljset);
|
||||
SDT_PROBE_DECLARE(mbuf, , , m__free);
|
||||
SDT_PROBE_DECLARE(mbuf, , , m__freem);
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
/*
|
||||
* Mbufs are of a single size, MSIZE (sys/param.h), which includes overhead.
|
||||
* An mbuf may add a single "mbuf cluster" of size MCLBYTES (also in
|
||||
@ -664,7 +692,7 @@ m_getzone(int size)
|
||||
static __inline int
|
||||
m_init(struct mbuf *m, int how, short type, int flags)
|
||||
{
|
||||
int error;
|
||||
int error = 0;
|
||||
|
||||
m->m_next = NULL;
|
||||
m->m_nextpkt = NULL;
|
||||
@ -672,42 +700,50 @@ m_init(struct mbuf *m, int how, short type, int flags)
|
||||
m->m_len = 0;
|
||||
m->m_flags = flags;
|
||||
m->m_type = type;
|
||||
if (flags & M_PKTHDR) {
|
||||
if ((error = m_pkthdr_init(m, how)) != 0)
|
||||
return (error);
|
||||
}
|
||||
if (flags & M_PKTHDR)
|
||||
error = m_pkthdr_init(m, how);
|
||||
|
||||
return (0);
|
||||
MBUF_PROBE5(m__init, m, how, type, flags, error);
|
||||
return (error);
|
||||
}
|
||||
|
||||
static __inline struct mbuf *
|
||||
m_get(int how, short type)
|
||||
{
|
||||
struct mbuf *m;
|
||||
struct mb_args args;
|
||||
|
||||
args.flags = 0;
|
||||
args.type = type;
|
||||
return (uma_zalloc_arg(zone_mbuf, &args, how));
|
||||
m = uma_zalloc_arg(zone_mbuf, &args, how);
|
||||
MBUF_PROBE3(m__get, how, type, m);
|
||||
return (m);
|
||||
}
|
||||
|
||||
static __inline struct mbuf *
|
||||
m_gethdr(int how, short type)
|
||||
{
|
||||
struct mbuf *m;
|
||||
struct mb_args args;
|
||||
|
||||
args.flags = M_PKTHDR;
|
||||
args.type = type;
|
||||
return (uma_zalloc_arg(zone_mbuf, &args, how));
|
||||
m = uma_zalloc_arg(zone_mbuf, &args, how);
|
||||
MBUF_PROBE3(m__gethdr, how, type, m);
|
||||
return (m);
|
||||
}
|
||||
|
||||
static __inline struct mbuf *
|
||||
m_getcl(int how, short type, int flags)
|
||||
{
|
||||
struct mbuf *m;
|
||||
struct mb_args args;
|
||||
|
||||
args.flags = flags;
|
||||
args.type = type;
|
||||
return (uma_zalloc_arg(zone_pack, &args, how));
|
||||
m = uma_zalloc_arg(zone_pack, &args, how);
|
||||
MBUF_PROBE4(m__getcl, how, type, flags, m);
|
||||
return (m);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -747,6 +783,7 @@ m_cljset(struct mbuf *m, void *cl, int type)
|
||||
m->m_ext.ext_flags = EXT_FLAG_EMBREF;
|
||||
m->m_ext.ext_count = 1;
|
||||
m->m_flags |= M_EXT;
|
||||
MBUF_PROBE3(m__cljset, m, cl, type);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
@ -1122,6 +1159,7 @@ m_free(struct mbuf *m)
|
||||
{
|
||||
struct mbuf *n = m->m_next;
|
||||
|
||||
MBUF_PROBE1(m__free, m);
|
||||
if ((m->m_flags & (M_PKTHDR|M_NOFREE)) == (M_PKTHDR|M_NOFREE))
|
||||
m_tag_delete_chain(m, NULL);
|
||||
if (m->m_flags & M_EXT)
|
||||
|
Loading…
x
Reference in New Issue
Block a user