From f5dec056ad3960ff2494697fb84cf263b2dcf644 Mon Sep 17 00:00:00 2001 From: Liu Hua Date: Sat, 12 Oct 2024 15:29:40 +0800 Subject: [PATCH] uffd: Disable image deduplication after fork After a fork, both the child and parent processes may trigger a page fault (#PF) at the same virtual address, referencing the same position in the page image. If deduplication is enabled, the last process to trigger the page fault will fail. Therefore, deduplication should be disabled after a fork to prevent this issue. Signed-off-by: Liu Hua --- criu/include/pagemap.h | 5 +++++ criu/pagemap.c | 11 ++++++++++- criu/uffd.c | 2 ++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/criu/include/pagemap.h b/criu/include/pagemap.h index 8c71805598..3ae15deb9c 100644 --- a/criu/include/pagemap.h +++ b/criu/include/pagemap.h @@ -58,6 +58,9 @@ struct page_read { /* Whether or not pages can be read in PIE code */ bool pieok; + /* Whether or not disable image deduplication*/ + bool disable_dedup; + /* Private data of reader */ struct cr_img *pmi; struct cr_img *pi; @@ -112,6 +115,8 @@ int pagemap_render_iovec(struct list_head *from, struct task_restore_args *ta); */ extern void dup_page_read(struct page_read *src, struct page_read *dst); +extern void page_read_disable_dedup(struct page_read *pr); + extern int dedup_one_iovec(struct page_read *pr, unsigned long base, unsigned long len); static inline unsigned long pagemap_len(PagemapEntry *pe) diff --git a/criu/pagemap.c b/criu/pagemap.c index 83f69bba37..85bb922596 100644 --- a/criu/pagemap.c +++ b/criu/pagemap.c @@ -261,7 +261,7 @@ static int read_local_page(struct page_read *pr, unsigned long vaddr, unsigned l break; } - if (opts.auto_dedup) { + if (opts.auto_dedup && !pr->disable_dedup) { ret = punch_hole(pr, pr->pi_off, len, false); if (ret == -1) return -1; @@ -792,6 +792,7 @@ int open_page_read_at(int dfd, unsigned long img_id, struct page_read *pr, int p pr->bunch.iov_base = NULL; pr->pmes = NULL; pr->pieok = false; + pr->disable_dedup = false; pr->pmi = open_image_at(dfd, i_typ, O_RSTR, img_id); if (!pr->pmi) @@ -852,6 +853,14 @@ int open_page_read(unsigned long img_id, struct page_read *pr, int pr_flags) #define DUP_IDS_BASE 1000 +void page_read_disable_dedup(struct page_read *pr) +{ + pr_debug("disable dedup, id: %d\n", pr->id); + pr->disable_dedup = true; + if (pr->parent) + page_read_disable_dedup(pr->parent); +} + void dup_page_read(struct page_read *src, struct page_read *dst) { static int dup_ids = 1; diff --git a/criu/uffd.c b/criu/uffd.c index e07b21b69c..98c2b7e075 100644 --- a/criu/uffd.c +++ b/criu/uffd.c @@ -1098,6 +1098,8 @@ static int handle_fork(struct lazy_pages_info *parent_lpi, struct uffd_msg *msg) lpi_get(lpi->parent); + page_read_disable_dedup(&parent_lpi->pr); + page_read_disable_dedup(&lpi->pr); return 1; out: