diff mbox

[v2,3/4] libibverbs: Undo changes in memory range tree when madvise() fails

Message ID 4B666D59.4000101@gmail.com (mailing list archive)
State Not Applicable, archived
Headers show

Commit Message

Alex Vainman Feb. 1, 2010, 5:57 a.m. UTC
None
diff mbox

Patch

diff --git a/src/memory.c b/src/memory.c
index 6a3305f..4dd9bdd 100644
--- a/src/memory.c
+++ b/src/memory.c
@@ -489,6 +489,39 @@  static struct ibv_mem_node *get_start_node(uintptr_t start, uintptr_t end,
 	return node;
 }
 
+/*
+ * This function is being called if madvise() fails and comes to
+ * undo merging/splitting operations performed on the node.
+ */
+static struct ibv_mem_node *undo_node(struct ibv_mem_node *node,
+				      uintptr_t start, int inc)
+{
+	struct ibv_mem_node *tmp = NULL;
+
+	/*
+	 * This condition can be true only if we merged this
+	 * node with the previous one, so we need to split them.
+	*/
+	if (start > node->start) {
+		tmp = split_range(node, start);
+		if (tmp) {
+			node->refcnt += inc;
+			node = tmp;
+		} else
+			return NULL;
+	}
+
+	tmp  =  __mm_prev(node);
+	if (tmp && tmp->refcnt == node->refcnt)
+		node = merge_ranges(node, tmp);
+
+	tmp  =  __mm_next(node);
+	if (tmp && tmp->refcnt == node->refcnt)
+		node = merge_ranges(tmp, node);
+
+	return node;
+}
+
 static int ibv_madvise_range(void *base, size_t size, int advice)
 {
 	uintptr_t start, end;
@@ -541,8 +574,10 @@  static int ibv_madvise_range(void *base, size_t size, int advice)
 				ret = madvise((void *) node->start,
 					      node->end - node->start + 1,
 					      advice);
-			if (ret)
+			if (ret) {
+				node = undo_node(node, start, inc);
 				goto out;
+			}
 		}
 
 		node->refcnt += inc;