From 60bd08b6a70cc0d7413dc4f80e64f07e6c31d274 Mon Sep 17 00:00:00 2001 From: Andrei Vagin Date: Thu, 5 Dec 2024 22:17:38 +0000 Subject: [PATCH] vdso: handle vvar_vclock vma-s The vvar_vclock was introduced by [1]. Basically, the old vvar vma has been splited on two parts. In term of C/R, these two vma-s can be still treated as one. [1] e93d2521b27f ("x86/vdso: Split virtual clock pages into dedicated mapping") Signed-off-by: Andrei Vagin --- criu/include/util-vdso.h | 1 + criu/pie/parasite-vdso.c | 19 ++++++++++++++++++- criu/proc_parse.c | 23 +++++++++++++++++++---- criu/vdso.c | 28 +++++++++++++++++++++------- 4 files changed, 59 insertions(+), 12 deletions(-) diff --git a/criu/include/util-vdso.h b/criu/include/util-vdso.h index c4386cf8ed..9fd9a6de4a 100644 --- a/criu/include/util-vdso.h +++ b/criu/include/util-vdso.h @@ -30,6 +30,7 @@ struct vdso_symbol { struct vdso_symtable { unsigned long vdso_size; unsigned long vvar_size; + unsigned long vvar_vclock_size; struct vdso_symbol symbols[VDSO_SYMBOL_MAX]; bool vdso_before_vvar; /* order of vdso/vvar pair */ }; diff --git a/criu/pie/parasite-vdso.c b/criu/pie/parasite-vdso.c index 355007fa92..f3ad3107fe 100644 --- a/criu/pie/parasite-vdso.c +++ b/criu/pie/parasite-vdso.c @@ -45,6 +45,7 @@ static int remap_one(char *who, unsigned long *from, unsigned long to, size_t si static int park_at(struct vdso_maps *rt, unsigned long vdso, unsigned long vvar) { unsigned long vvar_size = rt->sym.vvar_size; + unsigned long vvar_vclock_size = rt->sym.vvar_vclock_size; unsigned long vdso_size = rt->sym.vdso_size; int ret; @@ -54,8 +55,24 @@ static int park_at(struct vdso_maps *rt, unsigned long vdso, unsigned long vvar) std_log_set_gettimeofday(NULL); /* stop using vdso for timings */ - if (vvar) + if (vvar) { + /* + * v6.13-rc1~172^2~9 splits the vvar vma in two parts vvar and + * vvar_clock. The last one is mapped right after the first + * one. + */ + if (vvar_vclock_size) { + unsigned long from; + + vvar_size -= vvar_vclock_size; + from = rt->vvar_start + vvar_size; + + ret = remap_one("rt-vvar", &from, vvar + vvar_size, vvar_vclock_size); + if (ret) + return ret; + } ret = remap_one("rt-vvar", &rt->vvar_start, vvar, vvar_size); + } if (!ret) vdso_update_gtod_addr(rt); diff --git a/criu/proc_parse.c b/criu/proc_parse.c index 95ebe3a411..6c4303e7dd 100644 --- a/criu/proc_parse.c +++ b/criu/proc_parse.c @@ -579,7 +579,8 @@ static int handle_vma(pid_t pid, struct vma_area *vma_area, const char *file_pat } else if (!strcmp(file_path, "[vdso]")) { if (handle_vdso_vma(vma_area)) goto err; - } else if (!strcmp(file_path, "[vvar]")) { + } else if (!strcmp(file_path, "[vvar]") || + !strcmp(file_path, "[vvar_vclock]")) { if (handle_vvar_vma(vma_area)) goto err; } else if (!strcmp(file_path, "[heap]")) { @@ -771,7 +772,7 @@ static int task_size_check(pid_t pid, VmaEntry *entry) int parse_smaps(pid_t pid, struct vm_area_list *vma_area_list, dump_filemap_t dump_filemap) { - struct vma_area *vma_area = NULL; + struct vma_area *vma_area = NULL, *prev_vma_area = NULL; unsigned long start, end, pgoff, prev_end = 0; char r, w, x, s; int ret = -1, vm_file_fd = -1; @@ -813,8 +814,22 @@ int parse_smaps(pid_t pid, struct vm_area_list *vma_area_list, dump_filemap_t du continue; } - if (vma_area && vma_list_add(vma_area, vma_area_list, &prev_end, &vfi, &prev_vfi)) - goto err; + if (vma_area && vma_area_is(vma_area, VMA_AREA_VVAR) && + prev_vma_area && vma_area_is(prev_vma_area, VMA_AREA_VVAR)) { + if (prev_vma_area->e->end != vma_area->e->start) { + pr_err("two nonconsecutive vvar vma-s: " + "%" PRIx64 "-%" PRIx64 " %" PRIx64 "-%" PRIx64 "\n", + prev_vma_area->e->start, prev_vma_area->e->end, + vma_area->e->start, vma_area->e->end); + goto err; + } + /* Merge all vvar vma-s into one. */ + prev_vma_area->e->end = vma_area->e->end; + } else { + if (vma_area && vma_list_add(vma_area, vma_area_list, &prev_end, &vfi, &prev_vfi)) + goto err; + prev_vma_area = vma_area; + } if (eof) break; diff --git a/criu/vdso.c b/criu/vdso.c index 7de2fae784..d4d3511314 100644 --- a/criu/vdso.c +++ b/criu/vdso.c @@ -310,7 +310,7 @@ static int vdso_parse_maps(pid_t pid, struct vdso_maps *s) while (1) { unsigned long start, end; - char *has_vdso, *has_vvar; + char *has_vdso, *has_vvar, *has_vvar_vclock; buf = breadline(&f); if (buf == NULL) @@ -318,13 +318,19 @@ static int vdso_parse_maps(pid_t pid, struct vdso_maps *s) if (IS_ERR(buf)) goto err; - has_vdso = strstr(buf, "[vdso]"); - if (!has_vdso) + has_vvar = NULL; + has_vvar_vclock = NULL; + do { + has_vdso = strstr(buf, "[vdso]"); + if (has_vdso) + break; has_vvar = strstr(buf, "[vvar]"); - else - has_vvar = NULL; + if (has_vvar) + break; + has_vvar_vclock = strstr(buf, "[vvar_vclock]"); + } while (0); - if (!has_vdso && !has_vvar) + if (!has_vdso && !has_vvar && !has_vvar_vclock) continue; if (sscanf(buf, "%lx-%lx", &start, &end) != 2) { @@ -339,13 +345,21 @@ static int vdso_parse_maps(pid_t pid, struct vdso_maps *s) } s->vdso_start = start; s->sym.vdso_size = end - start; - } else { + } else if (has_vvar) { if (s->vvar_start != VVAR_BAD_ADDR) { pr_err("Got second VVAR entry\n"); goto err; } s->vvar_start = start; s->sym.vvar_size = end - start; + } else { + if (s->vvar_start == VDSO_BAD_ADDR || + s->vvar_start + s->sym.vvar_size != start) { + pr_err("VVAR and VVAR_VCLOCK entries are not subsequent\n"); + goto err; + } + s->sym.vvar_vclock_size = end - start; + s->sym.vvar_size += s->sym.vvar_vclock_size; } }