In order to support ongoing work to implement variable-size mbufs, and

more generally make it easier to extend 'struct mbuf in the future', make
a number of changes to the data structure:

- As we anticipate embedding mbufs headers within variable-size regions of
  memory in the future, change the definitions of byte arrays embedded in
  mbufs to be of size [0] rather than [MLEN] and [MHLEN].  In fact, the
  cxgbe driver already uses 'struct mbuf' on the front of other storage
  sizes, but we would like the global mbuf allocator do be able to do this
  as well.

- Fold 'struct m_hdr' into 'struct mbuf' itself, eliminating a set of
  macros that aliased 'mh_foo' field names to 'm_foo' names such as
  'm_next'.  These present a particular problem as we would like to add
  new mbuf-header fields -- e.g., 'm_size' -- that, if similarly named via
  macros, would introduce collisions with many other variable names in the
  kernel.

- Rename 'struct m_ext' to 'struct struct_m_ext' so that we can add
  compile-time assertions without bumping into the still-extant 'm_ext'
  macro.

- Remove the MSIZE compile-time assertion for 'struct mbuf', but add new
  assertions for alignment of embedded data arrays (64-bit alignment even
  on 32-bit platforms), and for the sizes the mbuf header, packet header,
  and m_ext structure.

- Document that these assertions exist in comments in mbuf.h.

This change is not intended to cause (non-trivial) behavioural
differences, but is a precursor to further mbuf-allocator work.

Differential Revision:	https://reviews.freebsd.org/D1483
Reviewed by:	bz, gnn, np, glebius ("go ahead, I trust you")
Sponsored by:	EMC / Isilon Storage Division
This commit is contained in:
Robert Watson 2015-01-14 23:44:00 +00:00
parent a2b8f1cbb7
commit 3d1a9ed34e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=277203
2 changed files with 68 additions and 31 deletions

View File

@ -88,10 +88,37 @@ SYSCTL_INT(_kern_ipc, OID_AUTO, m_defragrandomfailures, CTLFLAG_RW,
* Ensure the correct size of various mbuf parameters. It could be off due
* to compiler-induced padding and alignment artifacts.
*/
CTASSERT(sizeof(struct mbuf) == MSIZE);
CTASSERT(MSIZE - offsetof(struct mbuf, m_dat) == MLEN);
CTASSERT(MSIZE - offsetof(struct mbuf, m_pktdat) == MHLEN);
/*
* mbuf data storage should be 64-bit aligned regardless of architectural
* pointer size; check this is the case with and without a packet header.
*/
CTASSERT(offsetof(struct mbuf, m_dat) % 8 == 0);
CTASSERT(offsetof(struct mbuf, m_pktdat) % 8 == 0);
/*
* While the specific values here don't matter too much (i.e., +/- a few
* words), we do want to ensure that changes to these values are carefully
* reasoned about and properly documented. This is especially the case as
* network-protocol and device-driver modules encode these layouts, and must
* be recompiled if the structures change. Check these values at compile time
* against the ones documented in comments in mbuf.h.
*
* NB: Possibly they should be documented there via #define's and not just
* comments.
*/
#if defined(__LP64__)
CTASSERT(offsetof(struct mbuf, m_dat) == 32);
CTASSERT(sizeof(struct pkthdr) == 56);
CTASSERT(sizeof(struct struct_m_ext) == 48);
#else
CTASSERT(offsetof(struct mbuf, m_dat) == 24);
CTASSERT(sizeof(struct pkthdr) == 48);
CTASSERT(sizeof(struct struct_m_ext) == 28);
#endif
/*
* m_get2() allocates minimum mbuf that would fit "size" argument.
*/

View File

@ -60,9 +60,15 @@
* MLEN is data length in a normal mbuf.
* MHLEN is data length in an mbuf with pktheader.
* MINCLSIZE is a smallest amount of data that should be put into cluster.
*
* Compile-time assertions in uipc_mbuf.c test these values to ensure that
* they are sensible.
*/
#define MLEN ((int)(MSIZE - sizeof(struct m_hdr)))
#define MHLEN ((int)(MLEN - sizeof(struct pkthdr)))
struct mbuf;
#define MHSIZE offsetof(struct mbuf, M_dat.M_databuf)
#define MPKTHSIZE offsetof(struct mbuf, M_dat.MH.MH_dat.MH_databuf)
#define MLEN ((int)(MSIZE - MHSIZE))
#define MHLEN ((int)(MSIZE - MPKTHSIZE))
#define MINCLSIZE (MHLEN + 1)
#ifdef _KERNEL
@ -86,23 +92,6 @@ struct mb_args {
};
#endif /* _KERNEL */
/*
* Header present at the beginning of every mbuf.
* Size ILP32: 24
* LP64: 32
*/
struct m_hdr {
struct mbuf *mh_next; /* next buffer in chain */
struct mbuf *mh_nextpkt; /* next chain in queue/record */
caddr_t mh_data; /* location of data */
int32_t mh_len; /* amount of data in this mbuf */
uint32_t mh_type:8, /* type of data in this mbuf */
mh_flags:24; /* flags; see below */
#if !defined(__LP64__)
uint32_t mh_pad; /* pad for 64bit alignment */
#endif
};
/*
* Packet tag structure (see below for details).
*/
@ -118,6 +107,8 @@ struct m_tag {
* 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.
*/
struct pkthdr {
struct ifnet *rcvif; /* rcv interface */
@ -166,8 +157,10 @@ struct pkthdr {
* set.
* Size ILP32: 28
* LP64: 48
* Compile-time assertions in uipc_mbuf.c test these values to ensure that
* they are correct.
*/
struct m_ext {
struct 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 */
@ -184,24 +177,41 @@ struct m_ext {
* purposes.
*/
struct mbuf {
struct m_hdr m_hdr;
/*
* 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.
*/
struct mbuf *m_next; /* next buffer in chain */
struct mbuf *m_nextpkt; /* next chain in queue/record */
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 */
#if !defined(__LP64__)
uint32_t m_pad; /* pad for 64bit alignment */
#endif
/*
* 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 MH_pkthdr; /* M_PKTHDR set */
union {
struct m_ext MH_ext; /* M_EXT set */
char MH_databuf[MHLEN];
struct struct_m_ext MH_ext; /* M_EXT set */
char MH_databuf[0];
} MH_dat;
} MH;
char M_databuf[MLEN]; /* !M_PKTHDR, !M_EXT */
char M_databuf[0]; /* !M_PKTHDR, !M_EXT */
} M_dat;
};
#define m_next m_hdr.mh_next
#define m_len m_hdr.mh_len
#define m_data m_hdr.mh_data
#define m_type m_hdr.mh_type
#define m_flags m_hdr.mh_flags
#define m_nextpkt m_hdr.mh_nextpkt
#define m_pkthdr M_dat.MH.MH_pkthdr
#define m_ext M_dat.MH.MH_dat.MH_ext
#define m_pktdat M_dat.MH.MH_dat.MH_databuf