net: buf: move user_data to flexible arr member

Transition the `user_data` field in `struct net_buf` to be a flexible
array member instead of a hardcoded array. Compile-time asserts are
introduced at the location of the intermediate struct usage to ensure
that the assumptions utilised in runtime code hold true.

The primary assumptions are that the two `user_data` fields exist at the
same memory offset, and that the instantiated struct size can be
determined from the generic struct size and the length of the user data.

`net_buf_id` and `pool_get_uninit` must now use manual address
calculations as the `__bufs` type is no longer the actual size of the
instantiated variable.

Signed-off-by: Jordan Yates <jordan.yates@data61.csiro.au>
This commit is contained in:
Jordan Yates 2021-11-21 09:58:44 +10:00 committed by Johan Hedberg
commit bb780eff99
2 changed files with 25 additions and 10 deletions

View file

@ -963,7 +963,7 @@ struct net_buf {
}; };
/** System metadata for this buffer. */ /** System metadata for this buffer. */
uint8_t user_data[CONFIG_NET_BUF_USER_DATA_SIZE] __net_buf_align; uint8_t user_data[] __net_buf_align;
}; };
struct net_buf_data_cb { struct net_buf_data_cb {
@ -1033,7 +1033,7 @@ struct net_buf_pool {
.name = STRINGIFY(_pool), \ .name = STRINGIFY(_pool), \
.destroy = _destroy, \ .destroy = _destroy, \
.alloc = _alloc, \ .alloc = _alloc, \
.__bufs = _bufs, \ .__bufs = (struct net_buf *)_bufs, \
} }
#else #else
#define NET_BUF_POOL_INITIALIZER(_pool, _alloc, _bufs, _count, _ud_size, _destroy) \ #define NET_BUF_POOL_INITIALIZER(_pool, _alloc, _bufs, _count, _ud_size, _destroy) \
@ -1045,12 +1045,21 @@ struct net_buf_pool {
.user_data_size = _ud_size, \ .user_data_size = _ud_size, \
.destroy = _destroy, \ .destroy = _destroy, \
.alloc = _alloc, \ .alloc = _alloc, \
.__bufs = _bufs, \ .__bufs = (struct net_buf *)_bufs, \
} }
#endif /* CONFIG_NET_BUF_POOL_USAGE */ #endif /* CONFIG_NET_BUF_POOL_USAGE */
#define _NET_BUF_ARRAY_DEFINE(_name, _count) \ #define _NET_BUF_ARRAY_DEFINE(_name, _count, _ud_size) \
static struct net_buf _net_buf_##_name[_count] __noinit struct _net_buf_##_name {struct net_buf b; uint8_t ud[_ud_size]; }; \
BUILD_ASSERT(_ud_size <= UINT8_MAX); \
BUILD_ASSERT(offsetof(struct net_buf, user_data) == \
offsetof(struct _net_buf_##_name, ud), "Invalid offset"); \
BUILD_ASSERT(__alignof__(struct net_buf) == \
__alignof__(struct _net_buf_##_name), "Invalid alignment"); \
BUILD_ASSERT(sizeof(struct _net_buf_##_name) == \
ROUND_UP(sizeof(struct net_buf) + _ud_size, __alignof__(struct net_buf)), \
"Size cannot be determined"); \
static struct _net_buf_##_name _net_buf_##_name[_count] __noinit
extern const struct net_buf_data_alloc net_buf_heap_alloc; extern const struct net_buf_data_alloc net_buf_heap_alloc;
/** @endcond */ /** @endcond */
@ -1082,7 +1091,7 @@ extern const struct net_buf_data_alloc net_buf_heap_alloc;
* @param _destroy Optional destroy callback when buffer is freed. * @param _destroy Optional destroy callback when buffer is freed.
*/ */
#define NET_BUF_POOL_HEAP_DEFINE(_name, _count, _destroy) \ #define NET_BUF_POOL_HEAP_DEFINE(_name, _count, _destroy) \
_NET_BUF_ARRAY_DEFINE(_name, _count); \ _NET_BUF_ARRAY_DEFINE(_name, _count, CONFIG_NET_BUF_USER_DATA_SIZE); \
static struct net_buf_pool _name __net_buf_align \ static struct net_buf_pool _name __net_buf_align \
__in_section(_net_buf_pool, static, _name) = \ __in_section(_net_buf_pool, static, _name) = \
NET_BUF_POOL_INITIALIZER(_name, &net_buf_heap_alloc, \ NET_BUF_POOL_INITIALIZER(_name, &net_buf_heap_alloc, \
@ -1127,7 +1136,7 @@ extern const struct net_buf_data_cb net_buf_fixed_cb;
* @param _destroy Optional destroy callback when buffer is freed. * @param _destroy Optional destroy callback when buffer is freed.
*/ */
#define NET_BUF_POOL_FIXED_DEFINE(_name, _count, _data_size, _destroy) \ #define NET_BUF_POOL_FIXED_DEFINE(_name, _count, _data_size, _destroy) \
_NET_BUF_ARRAY_DEFINE(_name, _count); \ _NET_BUF_ARRAY_DEFINE(_name, _count, CONFIG_NET_BUF_USER_DATA_SIZE); \
static uint8_t __noinit net_buf_data_##_name[_count][_data_size]; \ static uint8_t __noinit net_buf_data_##_name[_count][_data_size]; \
static const struct net_buf_pool_fixed net_buf_fixed_##_name = { \ static const struct net_buf_pool_fixed net_buf_fixed_##_name = { \
.data_size = _data_size, \ .data_size = _data_size, \
@ -1172,7 +1181,7 @@ extern const struct net_buf_data_cb net_buf_var_cb;
* @param _destroy Optional destroy callback when buffer is freed. * @param _destroy Optional destroy callback when buffer is freed.
*/ */
#define NET_BUF_POOL_VAR_DEFINE(_name, _count, _data_size, _destroy) \ #define NET_BUF_POOL_VAR_DEFINE(_name, _count, _data_size, _destroy) \
_NET_BUF_ARRAY_DEFINE(_name, _count); \ _NET_BUF_ARRAY_DEFINE(_name, _count, CONFIG_NET_BUF_USER_DATA_SIZE); \
K_HEAP_DEFINE(net_buf_mem_pool_##_name, _data_size); \ K_HEAP_DEFINE(net_buf_mem_pool_##_name, _data_size); \
static const struct net_buf_data_alloc net_buf_data_alloc_##_name = { \ static const struct net_buf_data_alloc net_buf_data_alloc_##_name = { \
.cb = &net_buf_var_cb, \ .cb = &net_buf_var_cb, \

View file

@ -58,16 +58,22 @@ static int pool_id(struct net_buf_pool *pool)
int net_buf_id(struct net_buf *buf) int net_buf_id(struct net_buf *buf)
{ {
struct net_buf_pool *pool = net_buf_pool_get(buf->pool_id); struct net_buf_pool *pool = net_buf_pool_get(buf->pool_id);
size_t struct_size = ROUND_UP(sizeof(struct net_buf) + pool->user_data_size,
__alignof__(struct net_buf));
ptrdiff_t offset = (uint8_t *)buf - (uint8_t *)pool->__bufs;
return buf - pool->__bufs; return offset / struct_size;
} }
static inline struct net_buf *pool_get_uninit(struct net_buf_pool *pool, static inline struct net_buf *pool_get_uninit(struct net_buf_pool *pool,
uint16_t uninit_count) uint16_t uninit_count)
{ {
size_t struct_size = ROUND_UP(sizeof(struct net_buf) + pool->user_data_size,
__alignof__(struct net_buf));
size_t byte_offset = (pool->buf_count - uninit_count) * struct_size;
struct net_buf *buf; struct net_buf *buf;
buf = &pool->__bufs[pool->buf_count - uninit_count]; buf = (struct net_buf *)(((uint8_t *)pool->__bufs) + byte_offset);
buf->pool_id = pool_id(pool); buf->pool_id = pool_id(pool);
buf->user_data_size = pool->user_data_size; buf->user_data_size = pool->user_data_size;