Date: Tue, 19 Aug 2014 11:04:25 +0000 (UTC) From: Hans Petter Selasky <hselasky@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org Subject: svn commit: r270166 - stable/10/sys/ofed/include/linux Message-ID: <201408191104.s7JB4Pp0074119@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: hselasky Date: Tue Aug 19 11:04:24 2014 New Revision: 270166 URL: http://svnweb.freebsd.org/changeset/base/270166 Log: MFC r269859: Fix for memory leak. Sponsored by: Mellanox Technologies Modified: stable/10/sys/ofed/include/linux/linux_radix.c Directory Properties: stable/10/ (props changed) Modified: stable/10/sys/ofed/include/linux/linux_radix.c ============================================================================== --- stable/10/sys/ofed/include/linux/linux_radix.c Tue Aug 19 09:02:58 2014 (r270165) +++ stable/10/sys/ofed/include/linux/linux_radix.c Tue Aug 19 11:04:24 2014 (r270166) @@ -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; - /* - * Expand the tree to fit indexes as big as requested. - */ - while (root->rnode == NULL || radix_max(root) < index) { + /* 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); - node->slots[0] = root->rnode; - if (root->rnode) - node->count++; root->rnode = node; root->height++; } - node = root->rnode; - height = root->height - 1; - /* - * Walk down the tree finding the correct node and allocating any - * missing nodes along the way. - */ - while (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) + + /* 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); + + /* + * If the root radix level is not empty, we need to + * allocate a new radix level: + */ + 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; node->count++; + root->rnode = node; } + root->height++; + } + + /* get radix tree height index */ + height = root->height - 1; + + /* 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) + break; + node = node->slots[idx]; + } + + /* 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]; - height--; } + /* * Insert and adjust count if the item does not already exist. */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201408191104.s7JB4Pp0074119>