From b5dff62e3b136e48393d4c7589e74cfa7ebed9f5 Mon Sep 17 00:00:00 2001 From: Andrey Vagin Date: Sat, 8 Feb 2014 23:16:45 +0400 Subject: [PATCH] mem: use chunk mode for dumping anonymous memory Before this patch, criu splices all data in pipes and then saves these data in a image file. Here is a problem, becase creating pipes with big buffers fails too often, because a kernel tries to allocate a big linear chunks of memory. Now memory are dumped for a few iterations, where the size of pipe buffers is restricted. TODO: need to rework pre-dump, because currently dumping data from pipes are postponed. We are going to use sys_process_vm_readv for this. Signed-off-by: Andrey Vagin Signed-off-by: Pavel Emelyanov --- mem.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/mem.c b/mem.c index b143b5a30..65a1b7a7d 100644 --- a/mem.c +++ b/mem.c @@ -105,14 +105,15 @@ static inline bool page_in_parent(u64 pme) * the memory contents is present in the pagent image set. */ -static int generate_iovs(struct vma_area *vma, int pagemap, struct page_pipe *pp, u64 *map) +static int generate_iovs(struct vma_area *vma, int pagemap, + struct page_pipe *pp, u64 *map, u64 *off) { unsigned long pfn, nr_to_scan; unsigned long pages[2] = {}; u64 from, len; - nr_to_scan = vma_area_len(vma) / PAGE_SIZE; - from = vma->e->start / PAGE_SIZE * sizeof(*map); + nr_to_scan = (vma_area_len(vma) - *off) / PAGE_SIZE; + from = (vma->e->start + *off) / PAGE_SIZE * sizeof(*map); len = nr_to_scan * sizeof(*map); if (pread(pagemap, map, len, from) != len) { pr_perror("Can't read pagemap file"); @@ -126,7 +127,7 @@ static int generate_iovs(struct vma_area *vma, int pagemap, struct page_pipe *pp if (!should_dump_page(vma->e, map[pfn])) continue; - vaddr = vma->e->start + pfn * PAGE_SIZE; + vaddr = vma->e->start + *off + pfn * PAGE_SIZE; /* * If we're doing incremental dump (parent images @@ -143,10 +144,14 @@ static int generate_iovs(struct vma_area *vma, int pagemap, struct page_pipe *pp pages[1]++; } - if (ret) - return -1; + if (ret) { + *off += (pfn - 1) * PAGE_SIZE; + return ret; + } } + *off += pfn * PAGE_SIZE; + cnt_add(CNT_PAGES_SCANNED, nr_to_scan); cnt_add(CNT_PAGES_SKIPPED_PARENT, pages[0]); cnt_add(CNT_PAGES_WRITTEN, pages[1]); @@ -262,7 +267,8 @@ static int __parasite_dump_pages_seized(struct parasite_ctl *ctl, goto out_free; ret = -1; - pp = create_page_pipe(vma_area_list->priv_size / 2, pargs_iovs(args), false); + pp = create_page_pipe(vma_area_list->priv_size / 2, + pargs_iovs(args), pp_ret == NULL); if (!pp) goto out_close; @@ -270,7 +276,6 @@ static int __parasite_dump_pages_seized(struct parasite_ctl *ctl, ret = open_page_xfer(&xfer, CR_FD_PAGEMAP, ctl->pid.virt); if (ret < 0) goto out_pp; - } /* @@ -278,10 +283,21 @@ static int __parasite_dump_pages_seized(struct parasite_ctl *ctl, */ args->off = 0; list_for_each_entry(vma_area, &vma_area_list->h, list) { + u64 off = 0; + if (!privately_dump_vma(vma_area)) continue; +again: + ret = generate_iovs(vma_area, pagemap, pp, map, &off); + if (ret == -EAGAIN) { + BUG_ON(pp_ret); - ret = generate_iovs(vma_area, pagemap, pp, map); + ret = fill_pages(pp, ctl, args, &xfer); + if (ret) + goto out_xfer; + page_pipe_reinit(pp); + goto again; + } if (ret < 0) goto out_xfer; }