Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 19 Aug 2014 11:06:22 +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-9@freebsd.org
Subject:   svn commit: r270167 - stable/9/sys/ofed/include/linux
Message-ID:  <201408191106.s7JB6Mfo074459@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hselasky
Date: Tue Aug 19 11:06:21 2014
New Revision: 270167
URL: http://svnweb.freebsd.org/changeset/base/270167

Log:
  MFC r269859:
  Fix for memory leak.
  
  Sponsored by:	Mellanox Technologies

Modified:
  stable/9/sys/ofed/include/linux/linux_radix.c
Directory Properties:
  stable/9/sys/   (props changed)

Modified: stable/9/sys/ofed/include/linux/linux_radix.c
==============================================================================
--- stable/9/sys/ofed/include/linux/linux_radix.c	Tue Aug 19 11:04:24 2014	(r270166)
+++ stable/9/sys/ofed/include/linux/linux_radix.c	Tue Aug 19 11:06:21 2014	(r270167)
@@ -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?201408191106.s7JB6Mfo074459>