Skip to content

Commit 8619ea2

Browse files
mihalicynrst0git
authored andcommitted
criu/mem: dump: note MADV_GUARD pages as VMA_AREA_GUARD VMAs
Signed-off-by: Alexander Mikhalitsyn <[email protected]>
1 parent f091422 commit 8619ea2

File tree

3 files changed

+87
-0
lines changed

3 files changed

+87
-0
lines changed

criu/cr-dump.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,23 @@ int collect_mappings(pid_t pid, struct vm_area_list *vma_area_list, dump_filemap
130130
if (ret < 0)
131131
goto err;
132132

133+
/*
134+
* In addition to real process VMAs we should keep an info about
135+
* madvise(MADV_GUARD_INSTALL) pages. While these are not represented
136+
* as a struct vm_area_struct in the kernel, it is convenient to treat
137+
* them as mappings in CRIU and reuse the same VMA images but with only
138+
* VMA_AREA_GUARD flag set.
139+
*
140+
* Also, we don't need to dump them during pre-dump.
141+
*/
142+
if (dump_file) {
143+
ret = collect_madv_guards(pid, vma_area_list);
144+
if (ret < 0) {
145+
pr_err("Collect MADV_GUARD_INSTALL pages (pid: %d) failed with %d\n", pid, ret);
146+
goto err;
147+
}
148+
}
149+
133150
pr_info("Collected, longest area occupies %lu pages\n", vma_area_list->nr_priv_pages_longest);
134151
pr_info_vma_list(&vma_area_list->h);
135152

criu/include/mem.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ extern int do_task_reset_dirty_track(int pid);
3131
extern unsigned long dump_pages_args_size(struct vm_area_list *vmas);
3232
extern int parasite_dump_pages_seized(struct pstree_item *item, struct vm_area_list *vma_area_list,
3333
struct mem_dump_ctl *mdc, struct parasite_ctl *ctl);
34+
extern int collect_madv_guards(pid_t pid, struct vm_area_list *vma_area_list);
3435

3536
#define PME_PRESENT (1ULL << 63)
3637
#define PME_SWAP (1ULL << 62)

criu/mem.c

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1548,3 +1548,72 @@ int prepare_vmas(struct pstree_item *t, struct task_restore_args *ta)
15481548

15491549
return prepare_vma_ios(t, ta);
15501550
}
1551+
1552+
int collect_madv_guards(pid_t pid, struct vm_area_list *vma_area_list)
1553+
{
1554+
int pagemap_fd = -1;
1555+
struct page_region *regs = NULL;
1556+
long regs_len = 0;
1557+
int i, ret = -1;
1558+
1559+
struct pm_scan_arg args = {
1560+
.size = sizeof(struct pm_scan_arg),
1561+
.flags = 0,
1562+
.start = 0,
1563+
.end = kdat.task_size,
1564+
.walk_end = 0,
1565+
.vec_len = 1000, /* this should be enough for most cases */
1566+
.max_pages = 0,
1567+
.category_mask = PAGE_IS_GUARD,
1568+
.return_mask = PAGE_IS_GUARD,
1569+
};
1570+
1571+
if (!kdat.has_pagemap_scan_guard_pages) {
1572+
ret = 0;
1573+
goto out;
1574+
}
1575+
1576+
pagemap_fd = open_proc(pid, "pagemap");
1577+
if (pagemap_fd < 0)
1578+
goto out;
1579+
1580+
regs = xmalloc(args.vec_len * sizeof(struct page_region));
1581+
if (!regs)
1582+
goto out;
1583+
args.vec = (long)regs;
1584+
1585+
do {
1586+
/* start from where we finished the last time */
1587+
args.start = args.walk_end;
1588+
regs_len = ioctl(pagemap_fd, PAGEMAP_SCAN, &args);
1589+
if (regs_len == -1) {
1590+
pr_perror("PAGEMAP_SCAN");
1591+
goto out;
1592+
}
1593+
1594+
for (i = 0; i < regs_len; i++) {
1595+
struct vma_area *vma;
1596+
1597+
BUG_ON(!(regs[i].categories & PAGE_IS_GUARD));
1598+
1599+
vma = alloc_vma_area();
1600+
if (!vma)
1601+
goto out;
1602+
1603+
vma->e->start = regs[i].start;
1604+
vma->e->end = regs[i].end;
1605+
vma->e->status = VMA_AREA_GUARD;
1606+
1607+
list_add_tail(&vma->list, &vma_area_list->h);
1608+
vma_area_list->nr++;
1609+
}
1610+
} while (args.walk_end != kdat.task_size);
1611+
1612+
ret = 0;
1613+
1614+
out:
1615+
xfree(regs);
1616+
if (pagemap_fd >= 0)
1617+
close(pagemap_fd);
1618+
return ret;
1619+
}

0 commit comments

Comments
 (0)