[CRIU] [PATCHv1 4/8] shmem: implement dirty page tracking for anon shared memory
Eugene Batalov
eabatalov89 at gmail.com
Wed Dec 16 05:12:12 PST 2015
From: Fyodor Bocharov<bocharovfedor at gmail.com>
To track anon shared vma pages dirtiness we create a bitmap for it.
Each bit in this bitmap corresponds to particular page in vma. Bit with
value of 1 in this map states that page is dirty. Bit 0 states that the
page is clean.
Now we can collect shared vmas in __parasite_dump_pages_seized routine
instead of doing it from dump_task_mm because there we have pagemaps of
dumpee but pmc should be big enough to hold the longest of private and
shared vmas.
Signed-off-by: Fyodor Bocharov <fbocharov at yandex.ru>
Signed-off-by: Eugene Batalov <eabatalov89 at gmail.com>
---
cr-dump.c | 2 --
include/shmem.h | 3 ++-
mem.c | 29 ++++++++++++++++++-----------
shmem.c | 47 ++++++++++++++++++++++++++++++++++++++++++++---
4 files changed, 64 insertions(+), 17 deletions(-)
diff --git a/cr-dump.c b/cr-dump.c
index d5ef044..86be74f 100644
--- a/cr-dump.c
+++ b/cr-dump.c
@@ -426,8 +426,6 @@ static int dump_task_mm(pid_t pid, const struct proc_pid_stat *stat,
ret = 0;
else if (vma_entry_is(vma, VMA_AREA_SYSVIPC))
ret = check_sysvipc_map_dump(pid, vma);
- else if (vma_entry_is(vma, VMA_ANON_SHARED))
- ret = add_shmem_area(pid, vma);
else if (vma_entry_is(vma, VMA_FILE_PRIVATE) ||
vma_entry_is(vma, VMA_FILE_SHARED))
ret = dump_filemap(pid, vma_area, imgset);
diff --git a/include/shmem.h b/include/shmem.h
index 47dd0fd..066b5c3 100644
--- a/include/shmem.h
+++ b/include/shmem.h
@@ -1,6 +1,7 @@
#ifndef __CR_SHMEM_H__
#define __CR_SHMEM_H__
+#include "asm/int.h"
#include "lock.h"
#include "protobuf/vma.pb-c.h"
@@ -10,6 +11,6 @@ extern void show_saved_shmems(void);
extern int get_shmem_fd(int pid, VmaEntry *vi);
extern int cr_dump_shmem(void);
-extern int add_shmem_area(pid_t pid, VmaEntry *vma);
+extern int add_shmem_area(pid_t pid, VmaEntry *vma, u64 *map);
#endif /* __CR_SHMEM_H__ */
diff --git a/mem.c b/mem.c
index 78cc2fe..c48a22b 100644
--- a/mem.c
+++ b/mem.c
@@ -246,6 +246,7 @@ static int __parasite_dump_pages_seized(struct parasite_ctl *ctl,
struct vma_area *vma_area;
struct page_xfer xfer = { .parent = NULL };
int ret = -1;
+ unsigned long pmc_size;
pr_info("\n");
pr_info("Dumping pages (type: %d pid: %d)\n", CR_FD_PAGES, ctl->pid.real);
@@ -262,8 +263,9 @@ static int __parasite_dump_pages_seized(struct parasite_ctl *ctl,
* Step 0 -- prepare
*/
+ pmc_size = max(vma_area_list->priv_longest, vma_area_list->shared_longest);
if (pmc_init(&pmc, ctl->pid.real, &vma_area_list->h,
- vma_area_list->priv_longest * PAGE_SIZE))
+ pmc_size * PAGE_SIZE))
return -1;
ret = -1;
@@ -293,22 +295,27 @@ static int __parasite_dump_pages_seized(struct parasite_ctl *ctl,
u64 off = 0;
u64 *map;
- if (!vma_area_is_private(vma_area, kdat.task_size))
+ if (!vma_area_is_private(vma_area, kdat.task_size) &&
+ !vma_area_is(vma_area, VMA_ANON_SHARED))
continue;
map = pmc_get_map(&pmc, vma_area);
if (!map)
goto out_xfer;
+ if (vma_area_is(vma_area, VMA_ANON_SHARED))
+ ret = add_shmem_area(ctl->pid.real, vma_area->e, map);
+ else {
again:
- ret = generate_iovs(vma_area, pp, map, &off, xfer.parent);
- if (ret == -EAGAIN) {
- BUG_ON(pp_ret);
-
- ret = dump_pages(pp, ctl, args, &xfer);
- if (ret)
- goto out_xfer;
- page_pipe_reinit(pp);
- goto again;
+ ret = generate_iovs(vma_area, pp, map, &off, xfer.parent);
+ if (ret == -EAGAIN) {
+ BUG_ON(pp_ret);
+
+ ret = dump_pages(pp, ctl, args, &xfer);
+ if (ret)
+ goto out_xfer;
+ page_pipe_reinit(pp);
+ goto again;
+ }
}
if (ret < 0)
goto out_xfer;
diff --git a/shmem.c b/shmem.c
index b2900f4..8563415 100644
--- a/shmem.c
+++ b/shmem.c
@@ -12,6 +12,7 @@
#include "page-xfer.h"
#include "rst-malloc.h"
#include "vma.h"
+#include "mem.h"
#include "protobuf.h"
#include "protobuf/pagemap.pb-c.h"
@@ -282,6 +283,7 @@ struct shmem_info_dump {
unsigned long start;
unsigned long end;
int pid;
+ unsigned long *pdirty_map;
struct shmem_info_dump *next;
};
@@ -289,6 +291,35 @@ struct shmem_info_dump {
#define SHMEM_HASH_SIZE 32
static struct shmem_info_dump *shmems_hash[SHMEM_HASH_SIZE];
+#define BLOCKS_CNT(size, block_size) (((size) + (block_size) - 1) / (block_size))
+
+static int expand_shmem_pdirty_map(struct shmem_info_dump *si, unsigned long mem_size)
+{
+ unsigned long nr_pages, size, new_size;
+
+ nr_pages = BLOCKS_CNT(si->size, PAGE_SIZE);
+ size = BLOCKS_CNT(nr_pages, sizeof(*si->pdirty_map));
+
+ nr_pages = BLOCKS_CNT(mem_size, PAGE_SIZE);
+ new_size = BLOCKS_CNT(nr_pages, sizeof(*si->pdirty_map));
+
+ si->pdirty_map = xrealloc(si->pdirty_map, new_size);
+ if (!si->pdirty_map)
+ return -1;
+ memzero((char *)si->pdirty_map + size, new_size - size);
+
+ return 0;
+}
+
+static void update_shmem_pdirty_map(struct shmem_info_dump *si, u64 *map)
+{
+ unsigned long p, pcount = BLOCKS_CNT(si->size, PAGE_SIZE);
+
+ for (p = 0; p < pcount; ++p)
+ if (map[p] & PME_SOFT_DIRTY)
+ set_bit(p, si->pdirty_map);
+}
+
static struct shmem_info_dump *shmem_find(struct shmem_info_dump **chain,
unsigned long shmid)
{
@@ -301,7 +332,7 @@ static struct shmem_info_dump *shmem_find(struct shmem_info_dump **chain,
return NULL;
}
-int add_shmem_area(pid_t pid, VmaEntry *vma)
+int add_shmem_area(pid_t pid, VmaEntry *vma, u64 *map)
{
struct shmem_info_dump *si, **chain;
unsigned long size = vma->pgoff + (vma->end - vma->start);
@@ -309,12 +340,18 @@ int add_shmem_area(pid_t pid, VmaEntry *vma)
chain = &shmems_hash[vma->shmid % SHMEM_HASH_SIZE];
si = shmem_find(chain, vma->shmid);
if (si) {
- if (si->size < size)
+ if (si->size < size) {
+ if (expand_shmem_pdirty_map(si, size))
+ return -1;
+
si->size = size;
+ }
+ update_shmem_pdirty_map(si, map);
+
return 0;
}
- si = xmalloc(sizeof(*si));
+ si = xzalloc(sizeof(*si));
if (!si)
return -1;
@@ -327,6 +364,10 @@ int add_shmem_area(pid_t pid, VmaEntry *vma)
si->end = vma->end;
si->shmid = vma->shmid;
+ if (expand_shmem_pdirty_map(si, size))
+ return -1;
+ update_shmem_pdirty_map(si, map);
+
return 0;
}
--
1.9.1
More information about the CRIU
mailing list