Commit 363812c9 authored by Andrey Vagin's avatar Andrey Vagin Committed by Pavel Emelyanov

restore: optimize restorer_get_vma_hint

It's an O(n) algorithm.

Now we iterate both lists simultaneously to find a hole.

[xemul: Discussion making the patch more understandable:

Cyrill:

	If s_vma is the last one on self_vma_list you could break immediately, no?

	And the snippet I somehow miss is -- how the situation handled when

		      hole
		    a      b
	source |----|      |-----|
	target   |----|      |-----|
		      c      d

	the hole fits the requested size but the hole is shifted
	in target, so that you've

	prev_vma_end = a

	and then you find that a - d > vma_len and return a
	as start address for new mapping while finally it
	might intersect with address c.

	Or I miss something obvious?

Andrey:

	Look at "continue" one more time.
	prev_vma_end is returned only if both condition are true

	if (prev_vma_end + vma_len > s_vma->vma.start) {
	....
	if (prev_vma_end + vma_len > t_vma->vma.start) {
	...
Signed-off-by: 's avatarAndrey Vagin <avagin@openvz.org>
Looks-good-to: Cyrill Gorcunov <gorcunov@openvz.org>
Signed-off-by: 's avatarPavel Emelyanov <xemul@parallels.com>
parent 2d4244d0
...@@ -859,39 +859,54 @@ static int restore_all_tasks(pid_t pid, struct cr_options *opts) ...@@ -859,39 +859,54 @@ static int restore_all_tasks(pid_t pid, struct cr_options *opts)
return restore_root_task(pid, 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, 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 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; 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 * Here we need some heuristics -- the VMA which restorer will
* belong to should not be unmapped, so we need to gueess out * belong to should not be unmapped, so we need to gueess out
* where to put it in. * 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) { s_vma = list_first_entry(self_vma_list, struct vma_area, list);
if (prev_vma_end && ((t_vma->vma.start - prev_vma_end) > vma_len)) { t_vma = list_first_entry(tgt_vma_list, struct vma_area, list);
struct vma_area *s_vma;
unsigned long prev_vma_end2 = 0;
list_for_each_entry(s_vma, self_vma_list, list) { while (1) {
if (prev_vma_end2 + vma_len > t_vma->vma.start) if (prev_vma_end + vma_len > s_vma->vma.start) {
break; if (s_vma->list.next == self_vma_list) {
if (prev_vma_end2 && (prev_vma_end2 >= prev_vma_end) && s_vma = &end_vma;
((s_vma->vma.start - prev_vma_end2) > vma_len)) continue;
return prev_vma_end2; }
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; return -1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment