During build phase ACL doing quite a lot of memory allocations
for relatively small temporary structures.
In theory each of such allocation can fail, so we need to handle
all these possible failures.
That adds a lot of extra checks and makes the code harder to read and follow.
To simplify the process, made changes to handle all such failures
in one place.
Note, that all that memory for temporary structures
is freed at one go at the end of build phase.
Signed-off-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
/* add room for more pointers */
num_ptrs = node->max_ptrs + ACL_PTR_ALLOC;
ptrs = acl_build_alloc(context, num_ptrs, sizeof(*ptrs));
/* add room for more pointers */
num_ptrs = node->max_ptrs + ACL_PTR_ALLOC;
ptrs = acl_build_alloc(context, num_ptrs, sizeof(*ptrs));
- if (ptrs == NULL)
- return -ENOMEM;
/* copy current points to new memory allocation */
if (node->ptrs != NULL) {
/* copy current points to new memory allocation */
if (node->ptrs != NULL) {
struct rte_acl_node *next;
next = acl_alloc_node(context, node->level);
struct rte_acl_node *next;
next = acl_alloc_node(context, node->level);
- if (next == NULL)
- return NULL;
/* allocate the pointers */
if (node->num_ptrs > 0) {
next->ptrs = acl_build_alloc(context,
node->max_ptrs,
sizeof(struct rte_acl_ptr_set));
/* allocate the pointers */
if (node->num_ptrs > 0) {
next->ptrs = acl_build_alloc(context,
node->max_ptrs,
sizeof(struct rte_acl_ptr_set));
- if (next->ptrs == NULL)
- return NULL;
next->max_ptrs = node->max_ptrs;
}
next->max_ptrs = node->max_ptrs;
}
/* Duplicate A for intersection */
node_c = acl_dup_node(context, node_a->ptrs[idx_a].ptr);
/* Duplicate A for intersection */
node_c = acl_dup_node(context, node_a->ptrs[idx_a].ptr);
- if (node_c == NULL)
- return -1;
/* Remove intersection from A */
acl_exclude_ptr(context, node_a, idx_a, intersect_ptr);
/* Remove intersection from A */
acl_exclude_ptr(context, node_a, idx_a, intersect_ptr);
rule = head;
trie = acl_alloc_node(context, 0);
rule = head;
trie = acl_alloc_node(context, 0);
- if (trie == NULL)
- return NULL;
while (rule != NULL) {
root = acl_alloc_node(context, 0);
while (rule != NULL) {
root = acl_alloc_node(context, 0);
- if (root == NULL)
- return NULL;
root->ref_count = 1;
end = root;
root->ref_count = 1;
end = root;
* Setup the results for this rule.
* The result and priority of each category.
*/
* Setup the results for this rule.
* The result and priority of each category.
*/
- if (end->mrt == NULL &&
- (end->mrt = acl_build_alloc(context, 1,
- sizeof(*end->mrt))) == NULL)
- return NULL;
+ if (end->mrt == NULL)
+ end->mrt = acl_build_alloc(context, 1,
+ sizeof(*end->mrt));
for (m = 0; m < context->cfg.num_categories; m++) {
if (rule->f->data.category_mask & (1 << m)) {
for (m = 0; m < context->cfg.num_categories; m++) {
if (rule->f->data.category_mask & (1 << m)) {
/* Create a new copy of config for remaining rules. */
config = acl_build_alloc(context, 1, sizeof(*config));
/* Create a new copy of config for remaining rules. */
config = acl_build_alloc(context, 1, sizeof(*config));
- if (config == NULL) {
- RTE_LOG(ERR, ACL,
- "New config allocation for %u-th "
- "trie failed\n", num_tries);
- return -ENOMEM;
- }
-
memcpy(config, rule_sets[n]->config, sizeof(*config));
/* Make remaining rules use new config. */
memcpy(config, rule_sets[n]->config, sizeof(*config));
/* Make remaining rules use new config. */
sz = ofs + n * fn * sizeof(*wp);
br = tb_alloc(&bcx->pool, sz);
sz = ofs + n * fn * sizeof(*wp);
br = tb_alloc(&bcx->pool, sz);
- if (br == NULL) {
- RTE_LOG(ERR, ACL, "ACL context %s: failed to create a copy "
- "of %u build rules (%zu bytes)\n",
- bcx->acx->name, n, sz);
- return -ENOMEM;
- }
wp = (uint32_t *)((uintptr_t)br + ofs);
num = 0;
wp = (uint32_t *)((uintptr_t)br + ofs);
num = 0;
bcx->category_mask = LEN2MASK(bcx->cfg.num_categories);
bcx->node_max = node_max;
bcx->category_mask = LEN2MASK(bcx->cfg.num_categories);
bcx->node_max = node_max;
+ rc = sigsetjmp(bcx->pool.fail, 0);
+
+ /* build phase runs out of memory. */
+ if (rc != 0) {
+ RTE_LOG(ERR, ACL,
+ "ACL context: %s, %s() failed with error code: %d\n",
+ bcx->acx->name, __func__, rc);
+ return rc;
+ }
+
/* Create a build rules copy. */
rc = acl_build_rules(bcx);
if (rc != 0)
/* Create a build rules copy. */
rc = acl_build_rules(bcx);
if (rc != 0)
* Memory management routines for temporary memory.
* That memory is used only during build phase and is released after
* build is finished.
* Memory management routines for temporary memory.
* That memory is used only during build phase and is released after
* build is finished.
+ * Note, that tb_pool/tb_alloc() are not supposed to return NULL.
+ * Instead, in the case of failure to allocate memory,
+ * it would do siglongjmp(pool->fail).
+ * It is responsibility of the caller to save the proper context/environment,
+ * in the pool->fail before calling tb_alloc() for the given pool first time.
*/
static struct tb_mem_block *
*/
static struct tb_mem_block *
if (block == NULL) {
RTE_LOG(ERR, MALLOC, "%s(%zu)\n failed, currently allocated "
"by pool: %zu bytes\n", __func__, sz, pool->alloc);
if (block == NULL) {
RTE_LOG(ERR, MALLOC, "%s(%zu)\n failed, currently allocated "
"by pool: %zu bytes\n", __func__, sz, pool->alloc);
+ siglongjmp(pool->fail, -ENOMEM);
if (block == NULL || block->size < size) {
new_sz = (size > pool->min_alloc) ? size : pool->min_alloc;
block = tb_pool(pool, new_sz);
if (block == NULL || block->size < size) {
new_sz = (size > pool->min_alloc) ? size : pool->min_alloc;
block = tb_pool(pool, new_sz);
- if (block == NULL)
- return NULL;
}
ptr = block->mem;
block->size -= size;
}
ptr = block->mem;
block->size -= size;
#endif
#include <rte_acl_osdep.h>
#endif
#include <rte_acl_osdep.h>
struct tb_mem_block {
struct tb_mem_block *next;
struct tb_mem_block {
struct tb_mem_block *next;
size_t alignment;
size_t min_alloc;
size_t alloc;
size_t alignment;
size_t min_alloc;
size_t alloc;
+ /* jump target in case of memory allocation failure. */
+ sigjmp_buf fail;
};
void *tb_alloc(struct tb_mem_pool *pool, size_t size);
};
void *tb_alloc(struct tb_mem_pool *pool, size_t size);