diff mbox

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

Message ID 4B666D56.4090708@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 4dd9bdd..876dced 100644
--- a/src/memory.c
+++ b/src/memory.c
@@ -522,12 +522,43 @@  static struct ibv_mem_node *undo_node(struct ibv_mem_node *node,
 	return node;
 }
 
+/*
+ * This function is being called if madvise() fails.
+ * The node which caused madvise() to fail may contain
+ * just a sub range of [start-end].
+ * So we need to undo all the successful changes (if any)
+ * already performed on a range [start - (node->prev)->end].
+ * This function finds the node to begin rescanning from,
+ * finds the end of the range to rescan and invert
+ * the operation type.
+ */
+static struct ibv_mem_node *prepare_to_roll_back(struct ibv_mem_node *node,
+						 uintptr_t start,
+						 uintptr_t *end,
+						 int *inc,
+						 int *advice)
+{
+	struct ibv_mem_node *tmp = NULL;
+
+	*inc *= -1;
+	*advice = *inc == 1 ? MADV_DONTFORK : MADV_DOFORK;
+	tmp = __mm_prev(node);
+	node = NULL;
+	if (tmp) {
+		*end = tmp->end;
+		if (start <= *end)
+			node = get_start_node(start, *end, *inc);
+	}
+	return node;
+}
+
 static int ibv_madvise_range(void *base, size_t size, int advice)
 {
 	uintptr_t start, end;
 	struct ibv_mem_node *node, *tmp;
 	int inc;
 	int ret = 0;
+	int rolling_back = 0;
 
 	if (!size)
 		return 0;
@@ -576,7 +607,13 @@  static int ibv_madvise_range(void *base, size_t size, int advice)
 					      advice);
 			if (ret) {
 				node = undo_node(node, start, inc);
-				goto out;
+				if (rolling_back || !node)
+					goto out;
+
+				node = prepare_to_roll_back(node, start, &end,
+							    &inc, &advice);
+				rolling_back = 1;
+				continue;
 			}
 		}