1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-13 10:02:38 +00:00

- Fix radix tree memory leakage when unloading modules using radix

trees. This happens because the logic inserting items into the radix
tree is allocating empty radix levels, when index zero does not
contain any items.
- Add proper error case handling, so that the radix tree does not end
up in a bad state, if memory cannot be allocated during insertion of
an item.
- Add check for inserting NULL items into the radix tree.
- Add check for radix tree getting too big.

MFC after:	1 week
Sponsored by:	Mellanox Technologies
This commit is contained in:
Hans Petter Selasky 2014-08-12 11:45:57 +00:00
parent c79bec9c75
commit 918ba0175b
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=269859

View File

@ -123,40 +123,84 @@ int
radix_tree_insert(struct radix_tree_root *root, unsigned long index, void *item)
{
struct radix_tree_node *node;
struct radix_tree_node *temp[RADIX_TREE_MAX_HEIGHT - 1];
int height;
int idx;
/* bail out upon insertion of a NULL item */
if (item == NULL)
return (-EINVAL);
/* get root node, if any */
node = root->rnode;
/* allocate root node, if any */
if (node == NULL) {
node = malloc(sizeof(*node), M_RADIX, root->gfp_mask | M_ZERO);
if (node == NULL)
return (-ENOMEM);
root->rnode = node;
root->height++;
}
/* expand radix tree as needed */
while (radix_max(root) < index) {
/* check if the radix tree is getting too big */
if (root->height == RADIX_TREE_MAX_HEIGHT)
return (-E2BIG);
/*
* Expand the tree to fit indexes as big as requested.
* If the root radix level is not empty, we need to
* allocate a new radix level:
*/
while (root->rnode == NULL || radix_max(root) < index) {
if (node->count != 0) {
node = malloc(sizeof(*node), M_RADIX, root->gfp_mask | M_ZERO);
if (node == NULL)
return (-ENOMEM);
node->slots[0] = root->rnode;
if (root->rnode)
node->count++;
root->rnode = node;
}
root->height++;
}
node = root->rnode;
/* get radix tree height index */
height = root->height - 1;
/*
* Walk down the tree finding the correct node and allocating any
* missing nodes along the way.
*/
while (height) {
/* walk down the tree until the first missing node, if any */
for ( ; height != 0; height--) {
idx = radix_pos(index, height);
if (node->slots[idx] == NULL) {
node->slots[idx] = malloc(sizeof(*node), M_RADIX,
root->gfp_mask | M_ZERO);
if (node->slots[idx] == NULL)
return (-ENOMEM);
node->count++;
}
break;
node = node->slots[idx];
height--;
}
/* allocate the missing radix levels, if any */
for (idx = 0; idx != height; idx++) {
temp[idx] = malloc(sizeof(*node), M_RADIX,
root->gfp_mask | M_ZERO);
if (temp[idx] == NULL) {
while(idx--)
free(temp[idx], M_RADIX);
/* check if we should free the root node aswell */
if (root->rnode->count == 0) {
free(root->rnode, M_RADIX);
root->rnode = NULL;
root->height = 0;
}
return (-ENOMEM);
}
}
/* setup new radix levels, if any */
for ( ; height != 0; height--) {
idx = radix_pos(index, height);
node->slots[idx] = temp[height - 1];
node->count++;
node = node->slots[idx];
}
/*
* Insert and adjust count if the item does not already exist.
*/