[CRIU] [PATCH cr] restore: optimize restorer_get_vma_hint

Andrey Vagin avagin at openvz.org
Sat Apr 7 03:09:29 EDT 2012


It's an O(n) algorithm.

Now we iterate both lists simultaneously to find a hole.

Signed-off-by: Andrey Vagin <avagin at openvz.org>
---
 cr-restore.c |   49 ++++++++++++++++++++++++++++++++-----------------
 1 files changed, 32 insertions(+), 17 deletions(-)

diff --git a/cr-restore.c b/cr-restore.c
index 2162fc1..8405336 100644
--- a/cr-restore.c
+++ b/cr-restore.c
@@ -870,39 +870,54 @@ static int restore_all_tasks(pid_t pid, struct cr_options *opts)
 	return restore_root_task(pid, opts);
 }
 
+#define TASK_SIZE_MAX   ((1UL << 47) - PAGE_SIZE)
 static long restorer_get_vma_hint(pid_t pid, struct list_head *tgt_vma_list,
 		struct list_head *self_vma_list, long vma_len)
 {
-	struct vma_area *t_vma;
+	struct vma_area *t_vma, *s_vma;
 	long prev_vma_end = 0;
+	struct vma_area end_vma;
+
+	end_vma.vma.start = end_vma.vma.end = TASK_SIZE_MAX;
+	prev_vma_end = PAGE_SIZE;
 
 	/*
 	 * Here we need some heuristics -- the VMA which restorer will
 	 * belong to should not be unmapped, so we need to gueess out
 	 * where to put it in.
-	 *
-	 * Yes, I know it's an O(n^2) algorithm, but usually there are
-	 * not that many VMAs presented so instead of consuming memory
-	 * better to stick with it.
 	 */
 
-	list_for_each_entry(t_vma, tgt_vma_list, list) {
-		if (prev_vma_end && ((t_vma->vma.start - prev_vma_end) > vma_len)) {
-			struct vma_area *s_vma;
-			unsigned long prev_vma_end2 = 0;
+	s_vma = list_first_entry(self_vma_list, struct vma_area, list);
+	t_vma = list_first_entry(tgt_vma_list, struct vma_area, list);
 
-			list_for_each_entry(s_vma, self_vma_list, list) {
-				if (prev_vma_end2 + vma_len > t_vma->vma.start)
-					break;
-				if (prev_vma_end2 && (prev_vma_end2 >= prev_vma_end) &&
-				    ((s_vma->vma.start - prev_vma_end2) > vma_len))
-					return prev_vma_end2;
+	while (1) {
+		if (prev_vma_end + vma_len > s_vma->vma.start) {
+			if (s_vma->list.next == self_vma_list) {
+				s_vma = &end_vma;
+				continue;
+			}
+			if (s_vma == &end_vma)
+				break;
+			if (prev_vma_end < s_vma->vma.end)
+				prev_vma_end = s_vma->vma.end;
+			s_vma = list_entry(s_vma->list.next, struct vma_area, list);
+			continue;
+		}
 
-				prev_vma_end2 = s_vma->vma.end;
+		if (prev_vma_end + vma_len > t_vma->vma.start) {
+			if (t_vma->list.next == tgt_vma_list) {
+				t_vma = &end_vma;
+				continue;
 			}
+			if (t_vma == &end_vma)
+				break;
+			if (prev_vma_end < t_vma->vma.end)
+				prev_vma_end = t_vma->vma.end;
+			t_vma = list_entry(t_vma->list.next, struct vma_area, list);
+			continue;
 		}
 
-		prev_vma_end = t_vma->vma.end;
+		return prev_vma_end;
 	}
 
 	return -1;
-- 
1.7.1



More information about the CRIU mailing list