Skip to content

Commit 4c04936

Browse files
committed
Don't dump pages which only contain zero bytes
Signed-off-by: Volker Simonis <[email protected]>
1 parent cda1c5c commit 4c04936

File tree

12 files changed

+172
-5
lines changed

12 files changed

+172
-5
lines changed

Documentation/criu.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,14 @@ mount -t cgroup -o devices,freezer none devices,freezer
369369
Deduplicate "old" data in pages images of previous *dump*. This option
370370
implies incremental *dump* mode (see the *pre-dump* command).
371371

372+
*--skip-zero-pages*::
373+
Don't dump pages containing only zero bytes. This is a
374+
potentially expensive operation because it checks for
375+
every single process page if it contains only zeros, but
376+
it can significantly decrease the image and improve the
377+
startup-timesize if many such pages exist. It effectively
378+
replaces such pages which the kernel's zero-page on restore.
379+
372380
*-l*, *--file-locks*::
373381
Dump file locks. It is necessary to make sure that all file lock users
374382
are taken into dump, so it is only safe to use this for enclosed containers

criu/config.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,7 @@ int parse_options(int argc, char **argv, bool *usage_error, bool *has_exec_cmd,
650650
{ "ms", no_argument, 0, 1054 },
651651
BOOL_OPT("track-mem", &opts.track_mem),
652652
BOOL_OPT("auto-dedup", &opts.auto_dedup),
653+
BOOL_OPT("skip-zero-pages", &opts.skip_zero_pages),
653654
{ "libdir", required_argument, 0, 'L' },
654655
{ "cpu-cap", optional_argument, 0, 1057 },
655656
BOOL_OPT("force-irmap", &opts.force_irmap),

criu/cr-service.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,9 @@ static int setup_opts_from_req(int sk, CriuOpts *req)
541541
if (req->has_auto_dedup)
542542
opts.auto_dedup = req->auto_dedup;
543543

544+
if (req->has_skip_zero_pages)
545+
opts.skip_zero_pages = req->skip_zero_pages;
546+
544547
if (req->has_force_irmap)
545548
opts.force_irmap = req->force_irmap;
546549

criu/crtools.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,7 @@ int main(int argc, char *argv[], char *envp[])
541541
" pages images of previous dump\n"
542542
" when used on restore, as soon as page is restored, it\n"
543543
" will be punched from the image\n"
544+
" --skip-zero-pages don't dump pages containing only zero bytes.\n"
544545
" --pre-dump-mode splice - parasite based pre-dumping (default)\n"
545546
" read - process_vm_readv syscall based pre-dumping\n"
546547
"\n"

criu/include/cr_options.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ struct cr_options {
157157
int track_mem;
158158
char *img_parent;
159159
int auto_dedup;
160+
int skip_zero_pages;
160161
unsigned int cpu_cap;
161162
int force_irmap;
162163
char **exec_cmd;

criu/mem.c

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
#include <sys/mman.h>
44
#include <errno.h>
55
#include <fcntl.h>
6+
#include <string.h>
67
#include <sys/syscall.h>
78
#include <sys/prctl.h>
9+
#include <sys/uio.h>
810

911
#include "types.h"
1012
#include "cr_options.h"
@@ -31,6 +33,7 @@
3133
#include "prctl.h"
3234
#include "compel/infect-util.h"
3335
#include "pidfd-store.h"
36+
#include "xmalloc.h"
3437

3538
#include "protobuf.h"
3639
#include "images/pagemap.pb-c.h"
@@ -172,17 +175,58 @@ static int generate_iovs(struct pstree_item *item, struct vma_area *vma, struct
172175
unsigned long pages[3] = {};
173176
int ret = 0;
174177

178+
static char *zero_page = NULL;
179+
static char *remote_page = NULL;
180+
int zero = 0;
181+
struct iovec local[2];
182+
struct iovec remote[1];
183+
int nread = 0;
184+
if (opts.skip_zero_pages && zero_page == NULL) {
185+
zero_page = xmalloc(PAGE_SIZE);
186+
remote_page = xmalloc(PAGE_SIZE);
187+
if (zero_page == NULL || remote_page == NULL) {
188+
pr_warn("Can't allocate memory - disabling --skip-zero-pages\n");
189+
opts.skip_zero_pages = 0;
190+
} else {
191+
memzero(zero_page, PAGE_SIZE);
192+
local[0].iov_base = remote_page;
193+
local[0].iov_len = PAGE_SIZE;
194+
remote[0].iov_base = (void *) 0x0;
195+
remote[0].iov_len = PAGE_SIZE;
196+
}
197+
}
198+
175199
nr_to_scan = (vma_area_len(vma) - *off) / PAGE_SIZE;
176200

177201
for (pfn = 0; pfn < nr_to_scan; pfn++) {
178202
unsigned long vaddr;
179203
unsigned int ppb_flags = 0;
180204
int st;
181205

182-
if (!should_dump_page(vma->e, at[pfn]))
183-
continue;
184-
185206
vaddr = vma->e->start + *off + pfn * PAGE_SIZE;
207+
/*
208+
* If should_dump_page() returns true, it means the page is in the dumpees resident memory
209+
* (i.e. bit 63 of the page frame number 'at[pfn]' is set) but it is not the zero-page.
210+
*/
211+
if (should_dump_page(vma->e, at[pfn])) {
212+
if (opts.skip_zero_pages) {
213+
remote[0].iov_base = (void*)vaddr;
214+
nread = process_vm_readv(item->pid->real, local, 1, remote, 1, 0);
215+
if (nread == PAGE_SIZE) {
216+
zero = memcmp(zero_page, remote_page, PAGE_SIZE);
217+
/*
218+
* If the page contains just zeros we can treat it like the zero page and skip it.
219+
* At restore it will be replaced by a reference to the zero page and COWed if accessed.
220+
*/
221+
if (zero == 0) {
222+
pr_info("Zero page detected at virtual addr = %p\n", (void*)vaddr);
223+
continue;
224+
}
225+
}
226+
}
227+
} else {
228+
continue;
229+
}
186230

187231
if (vma_entry_can_be_lazy(vma->e) && !is_stack(item, vaddr))
188232
ppb_flags |= PPB_LAZY;

images/rpc.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ message criu_opts {
145145
optional bool leave_stopped = 69;
146146
optional bool display_stats = 70;
147147
optional bool log_to_stderr = 71;
148+
optional bool skip_zero_pages = 72;
148149
/* optional bool check_mounts = 128; */
149150
}
150151

lib/c/criu.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,17 @@ void criu_set_auto_dedup(bool auto_dedup)
387387
criu_local_set_auto_dedup(global_opts, auto_dedup);
388388
}
389389

390+
void criu_local_set_skip_zero_pages(criu_opts *opts, bool skip_zero_pages)
391+
{
392+
opts->rpc->has_skip_zero_pages = true;
393+
opts->rpc->skip_zero_pages = skip_zero_pages;
394+
}
395+
396+
void criu_set_skip_zero_pages(bool skip_zero_pages)
397+
{
398+
criu_local_set_skip_zero_pages(global_opts, skip_zero_pages);
399+
}
400+
390401
void criu_local_set_force_irmap(criu_opts *opts, bool force_irmap)
391402
{
392403
opts->rpc->has_force_irmap = true;

test/javaTests/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
<!-- Suite testng xml file to consider for test execution -->
1919
<suiteXmlFiles>
2020
<suiteXmlFile>test.xml</suiteXmlFile>
21+
<suiteXmlFile>test-zero.xml</suiteXmlFile>
2122
</suiteXmlFiles>
2223
</configuration>
2324
</plugin>

test/javaTests/src/org/criu/java/tests/CheckpointRestore.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ public void runtest(String testName, String checkpointOpt, String restoreOpt) th
112112
String pid;
113113
int exitCode;
114114

115-
System.out.println("======= Testing " + testName + " ========");
115+
System.out.println("======= Testing " + testName + " " + checkpointOpt + " ========");
116116

117117
testSetup(testName);
118118

test/javaTests/test-zero.xml

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?xml version = "1.0" encoding = "UTF-8"?>
2+
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
3+
4+
<suite name = "Suite2">
5+
<parameter name="checkpointOpt" value="--zero-pages"/>
6+
<parameter name="restoreOpt" value=""/>
7+
8+
<test name = "test1-FileRead">
9+
<parameter name="testname" value="FileRead"/>
10+
<classes>
11+
<class name = "org.criu.java.tests.CheckpointRestore"/>
12+
</classes>
13+
</test>
14+
15+
<test name = "test2-ReadWrite">
16+
<parameter name="testname" value="ReadWrite"/>
17+
<classes>
18+
<class name = "org.criu.java.tests.CheckpointRestore"/>
19+
</classes>
20+
</test>
21+
22+
<test name = "test3-MemoryMappings">
23+
<parameter name="testname" value="MemoryMappings"/>
24+
<classes>
25+
<class name = "org.criu.java.tests.CheckpointRestore"/>
26+
</classes>
27+
</test>
28+
29+
<test name = "test4-MultipleFileRead">
30+
<parameter name="testname" value="MultipleFileRead"/>
31+
<classes>
32+
<class name = "org.criu.java.tests.CheckpointRestore"/>
33+
</classes>
34+
</test>
35+
36+
<test name = "test5-MultipleFileWrite">
37+
<parameter name="testname" value="MultipleFileWrite"/>
38+
<classes>
39+
<class name = "org.criu.java.tests.CheckpointRestore"/>
40+
</classes>
41+
</test>
42+
43+
<test name = "test6-Sockets">
44+
<parameter name="testname" value="Sockets"/>
45+
<parameter name="checkpointOpt" value="--tcp-established --zero-pages"/>
46+
<parameter name="restoreOpt" value="--tcp-established"/>
47+
<classes>
48+
<class name = "org.criu.java.tests.CheckpointRestore"/>
49+
</classes>
50+
</test>
51+
52+
<test name = "test7-SocketsListen">
53+
<parameter name="testname" value="SocketsListen"/>
54+
<parameter name="checkpointOpt" value="--tcp-established --zero-pages"/>
55+
<parameter name="restoreOpt" value="--tcp-established"/>
56+
<classes>
57+
<class name = "org.criu.java.tests.CheckpointRestore"/>
58+
</classes>
59+
</test>
60+
61+
<test name = "test8-SocketsConnect">
62+
<parameter name="testname" value="SocketsConnect"/>
63+
<parameter name="checkpointOpt" value="--tcp-established --zero-pages"/>
64+
<parameter name="restoreOpt" value="--tcp-established"/>
65+
<classes>
66+
<class name = "org.criu.java.tests.CheckpointRestore"/>
67+
</classes>
68+
</test>
69+
70+
<test name = "test9-SocketsMultiple">
71+
<parameter name="testname" value="SocketsMultiple"/>
72+
<parameter name="checkpointOpt" value="--tcp-established --zero-pages"/>
73+
<parameter name="restoreOpt" value="--tcp-established"/>
74+
<classes>
75+
<class name = "org.criu.java.tests.CheckpointRestore"/>
76+
</classes>
77+
</test>
78+
79+
<test name = "test10-SocketsData">
80+
<parameter name="testname" value="SocketsData"/>
81+
<parameter name="checkpointOpt" value="--tcp-established --zero-pages"/>
82+
<parameter name="restoreOpt" value="--tcp-established"/>
83+
<classes>
84+
<class name = "org.criu.java.tests.CheckpointRestore"/>
85+
</classes>
86+
87+
</test>
88+
89+
</suite>

test/zdtm.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1052,6 +1052,7 @@ def __init__(self, opts):
10521052
self.__sat = bool(opts['sat'])
10531053
self.__dedup = bool(opts['dedup'])
10541054
self.__mdedup = bool(opts['noauto_dedup'])
1055+
self.__skip_zero_pages = bool(opts['skip_zero_pages'])
10551056
self.__user = bool(opts['user'])
10561057
self.__rootless = bool(opts['rootless'])
10571058
self.__leave_stopped = bool(opts['stop'])
@@ -1381,6 +1382,9 @@ def dump(self, action, opts=[]):
13811382
if self.__dedup:
13821383
a_opts += ["--auto-dedup"]
13831384

1385+
if self.__skip_zero_pages:
1386+
a_opts += ["--skip-zero-pages"]
1387+
13841388
a_opts += ["--timeout", "10"]
13851389

13861390
criu_dir = os.path.dirname(os.getcwd())
@@ -2083,7 +2087,7 @@ def run_test(self, name, desc, flavor):
20832087
'dedup', 'sbs', 'freezecg', 'user', 'dry_run', 'noauto_dedup',
20842088
'remote_lazy_pages', 'show_stats', 'lazy_migrate', 'stream',
20852089
'tls', 'criu_bin', 'crit_bin', 'pre_dump_mode', 'mntns_compat_mode',
2086-
'rootless')
2090+
'rootless', 'skip_zero_pages')
20872091
arg = repr((name, desc, flavor, {d: self.__opts[d] for d in nd}))
20882092

20892093
if self.__use_log:
@@ -2697,6 +2701,9 @@ def get_cli_args():
26972701
rp.add_argument("--noauto-dedup",
26982702
help="Manual deduplicate images on iterations",
26992703
action='store_true')
2704+
rp.add_argument("--skip-zero-pages",
2705+
help="Don't dump pages containing only zero bytes",
2706+
action='store_true')
27002707
rp.add_argument("--nocr",
27012708
help="Do not CR anything, just check test works",
27022709
action='store_true')

0 commit comments

Comments
 (0)