Branch data Line data Source code
1 : : #include <unistd.h>
2 : : #include <stdio.h>
3 : : #include <sys/mman.h>
4 : : #include <errno.h>
5 : : #include <fcntl.h>
6 : :
7 : : #include "cr_options.h"
8 : : #include "servicefd.h"
9 : : #include "mem.h"
10 : : #include "parasite-syscall.h"
11 : : #include "parasite.h"
12 : : #include "page-pipe.h"
13 : : #include "page-xfer.h"
14 : : #include "log.h"
15 : : #include "kerndat.h"
16 : : #include "stats.h"
17 : : #include "vma.h"
18 : : #include "shmem.h"
19 : : #include "pstree.h"
20 : : #include "restorer.h"
21 : : #include "files-reg.h"
22 : : #include "pagemap-cache.h"
23 : :
24 : : #include "protobuf.h"
25 : : #include "protobuf/pagemap.pb-c.h"
26 : :
27 : 3664 : static int task_reset_dirty_track(int pid)
28 : : {
29 [ + - ]: 3664 : if (!opts.track_mem)
30 : : return 0;
31 : :
32 [ - + ]: 3664 : BUG_ON(!kerndat_has_dirty_track);
33 : :
34 : 3664 : return do_task_reset_dirty_track(pid);
35 : : }
36 : :
37 : 5458 : int do_task_reset_dirty_track(int pid)
38 : : {
39 : : int fd, ret;
40 : 5458 : char cmd[] = "4";
41 : :
42 : 5458 : pr_info("Reset %d's dirty tracking\n", pid);
43 : :
44 [ - + ]: 5458 : fd = open_proc_rw(pid, "clear_refs");
45 [ + - ]: 5458 : if (fd < 0)
46 : : return -1;
47 : :
48 : 5458 : ret = write(fd, cmd, sizeof(cmd));
49 : 5458 : close(fd);
50 : :
51 [ - + ]: 5458 : if (ret < 0) {
52 : 0 : pr_warn("Can't reset %d's dirty memory tracker (%d)\n", pid, errno);
53 : 0 : return -1;
54 : : }
55 : :
56 : 5458 : pr_info(" ... done\n");
57 : 5458 : return 0;
58 : : }
59 : :
60 : 3664 : unsigned int dump_pages_args_size(struct vm_area_list *vmas)
61 : : {
62 : : /*
63 : : * In the worst case I need one iovec for half of the
64 : : * pages (e.g. every odd/even)
65 : : */
66 : :
67 : 14656 : return sizeof(struct parasite_dump_pages_args) +
68 : 7328 : vmas->nr * sizeof(struct parasite_vma_entry) +
69 : 7328 : (vmas->priv_size + 1) * sizeof(struct iovec) / 2;
70 : : }
71 : :
72 : 43773696 : static inline bool should_dump_page(VmaEntry *vmae, u64 pme)
73 : : {
74 [ + + ]: 21886848 : if (vma_entry_is(vmae, VMA_AREA_VDSO))
75 : : return true;
76 : : /*
77 : : * Optimisation for private mapping pages, that haven't
78 : : * yet being COW-ed
79 : : */
80 [ + + ][ + + ]: 21879520 : if (vma_entry_is(vmae, VMA_FILE_PRIVATE) && (pme & PME_FILE))
81 : : return false;
82 [ + - ]: 21641681 : if (pme & PME_SWAP)
83 : : return true;
84 [ + + ][ + + ]: 21641681 : if ((pme & PME_PRESENT) && ((pme & PME_PFRAME_MASK) != zero_page_pfn))
85 : : return true;
86 : :
87 : : return false;
88 : : }
89 : :
90 : : static inline bool page_in_parent(u64 pme)
91 : : {
92 : : /*
93 : : * If we do memory tracking, but w/o parent images,
94 : : * then we have to dump all memory
95 : : */
96 : :
97 [ + - ][ + + ]: 2348835 : return opts.track_mem && opts.img_parent && !(pme & PME_SOFT_DIRTY);
[ + + ]
98 : : }
99 : :
100 : : /*
101 : : * This routine finds out what memory regions to grab from the
102 : : * dumpee. The iovs generated are then fed into vmsplice to
103 : : * put the memory into the page-pipe's pipe.
104 : : *
105 : : * "Holes" in page-pipe are regions, that should be dumped, but
106 : : * the memory contents is present in the pagent image set.
107 : : */
108 : :
109 : 151400 : static int generate_iovs(struct vma_area *vma, struct page_pipe *pp, u64 *map, u64 *off, bool has_parent)
110 : : {
111 : 151400 : u64 *at = &map[PAGE_PFN(*off)];
112 : : unsigned long pfn, nr_to_scan;
113 : : unsigned long pages[2] = {};
114 : :
115 : 151400 : nr_to_scan = (vma_area_len(vma) - *off) / PAGE_SIZE;
116 : :
117 [ + + ]: 22038248 : for (pfn = 0; pfn < nr_to_scan; pfn++) {
118 : : unsigned long vaddr;
119 : : int ret;
120 : :
121 [ + + ]: 21886848 : if (!should_dump_page(vma->e, at[pfn]))
122 : 19537825 : continue;
123 : :
124 : 2349023 : vaddr = vma->e->start + *off + pfn * PAGE_SIZE;
125 : :
126 : : /*
127 : : * If we're doing incremental dump (parent images
128 : : * specified) and page is not soft-dirty -- we dump
129 : : * hole and expect the parent images to contain this
130 : : * page. The latter would be checked in page-xfer.
131 : : */
132 : :
133 [ + + ][ + + ]: 4697858 : if (has_parent && page_in_parent(at[pfn])) {
134 : 1658317 : ret = page_pipe_add_hole(pp, vaddr);
135 : 1658317 : pages[0]++;
136 : : } else {
137 : 690706 : ret = page_pipe_add_page(pp, vaddr);
138 : 690706 : pages[1]++;
139 : : }
140 : :
141 [ - + ]: 2349023 : if (ret) {
142 : 0 : *off += pfn * PAGE_SIZE;
143 : : return ret;
144 : : }
145 : : }
146 : :
147 : 151400 : *off += pfn * PAGE_SIZE;
148 : :
149 : 151400 : cnt_add(CNT_PAGES_SCANNED, nr_to_scan);
150 : 151400 : cnt_add(CNT_PAGES_SKIPPED_PARENT, pages[0]);
151 : 151400 : cnt_add(CNT_PAGES_WRITTEN, pages[1]);
152 : :
153 : 151400 : pr_info("Pagemap generated: %lu pages %lu holes\n", pages[1], pages[0]);
154 : : return 0;
155 : : }
156 : :
157 : 3664 : static struct parasite_dump_pages_args *prep_dump_pages_args(struct parasite_ctl *ctl,
158 : : struct vm_area_list *vma_area_list)
159 : : {
160 : : struct parasite_dump_pages_args *args;
161 : : struct parasite_vma_entry *p_vma;
162 : : struct vma_area *vma;
163 : :
164 : 3664 : args = parasite_args_s(ctl, dump_pages_args_size(vma_area_list));
165 : :
166 : 3664 : p_vma = pargs_vmas(args);
167 : 3664 : args->nr_vmas = 0;
168 : :
169 [ + + ]: 159248 : list_for_each_entry(vma, &vma_area_list->h, list) {
170 [ + + ]: 155584 : if (!privately_dump_vma(vma))
171 : 4184 : continue;
172 [ + + ]: 151400 : if (vma->e->prot & PROT_READ)
173 : 103138 : continue;
174 : :
175 : 48262 : p_vma->start = vma->e->start;
176 : 48262 : p_vma->len = vma_area_len(vma);
177 : 48262 : p_vma->prot = vma->e->prot;
178 : :
179 : 48262 : args->nr_vmas++;
180 : 48262 : p_vma++;
181 : : }
182 : :
183 : 3664 : return args;
184 : : }
185 : :
186 : 3664 : static int dump_pages(struct page_pipe *pp, struct parasite_ctl *ctl,
187 : : struct parasite_dump_pages_args *args, struct page_xfer *xfer)
188 : : {
189 : : struct page_pipe_buf *ppb;
190 : : int ret = 0;
191 : :
192 : 3664 : debug_show_page_pipe(pp);
193 : :
194 : : /* Step 2 -- grab pages into page-pipe */
195 [ + + ]: 8560 : list_for_each_entry(ppb, &pp->bufs, l) {
196 : 4896 : args->nr_segs = ppb->nr_segs;
197 : 4896 : args->nr_pages = ppb->pages_in;
198 : 4896 : pr_debug("PPB: %d pages %d segs %u pipe %d off\n",
199 : : args->nr_pages, args->nr_segs, ppb->pipe_size, args->off);
200 : :
201 : 4896 : ret = __parasite_execute_daemon(PARASITE_CMD_DUMPPAGES, ctl);
202 [ + - ]: 4896 : if (ret < 0)
203 : : return -1;
204 : 4896 : ret = parasite_send_fd(ctl, ppb->p[1]);
205 [ + - ]: 4896 : if (ret)
206 : : return -1;
207 : :
208 : 4896 : ret = __parasite_wait_daemon_ack(PARASITE_CMD_DUMPPAGES, ctl);
209 [ + - ]: 4896 : if (ret < 0)
210 : : return -1;
211 : :
212 : 4896 : args->off += args->nr_segs;
213 : : }
214 : :
215 : : /*
216 : : * Step 3 -- write pages into image (or delay writing for
217 : : * pre-dump action (see pre_dump_one_task)
218 : : */
219 [ + + ]: 3664 : if (xfer) {
220 : 919 : timing_start(TIME_MEMWRITE);
221 : 919 : ret = page_xfer_dump_pages(xfer, pp, 0);
222 : 919 : timing_stop(TIME_MEMWRITE);
223 : : }
224 : :
225 : 3664 : return ret;
226 : : }
227 : :
228 : 3664 : static int __parasite_dump_pages_seized(struct parasite_ctl *ctl,
229 : : struct parasite_dump_pages_args *args,
230 : : struct vm_area_list *vma_area_list,
231 : : struct page_pipe **pp_ret)
232 : : {
233 : 3664 : pmc_t pmc = PMC_INIT;
234 : : struct page_pipe *pp;
235 : : struct vma_area *vma_area;
236 : : struct page_xfer xfer;
237 : : int ret = -1;
238 : :
239 : 3664 : pr_info("\n");
240 : 3664 : pr_info("Dumping pages (type: %d pid: %d)\n", CR_FD_PAGES, ctl->pid.real);
241 : 3664 : pr_info("----------------------------------------\n");
242 : :
243 [ - + ]: 3664 : BUG_ON(zero_page_pfn == 0);
244 : :
245 : 3664 : timing_start(TIME_MEMDUMP);
246 : :
247 : 3664 : pr_debug(" Private vmas %lu/%lu pages\n",
248 : : vma_area_list->longest, vma_area_list->priv_size);
249 : :
250 : : /*
251 : : * Step 0 -- prepare
252 : : */
253 : :
254 [ + - ]: 3664 : if (pmc_init(&pmc, ctl->pid.real, &vma_area_list->h,
255 : 3664 : vma_area_list->longest * PAGE_SIZE))
256 : : return -1;
257 : :
258 : : ret = -1;
259 : 3664 : pp = create_page_pipe(vma_area_list->priv_size / 2,
260 : : pargs_iovs(args), pp_ret == NULL);
261 [ + - ]: 3664 : if (!pp)
262 : : goto out;
263 : :
264 [ + + ]: 3664 : if (pp_ret == NULL) {
265 : 919 : ret = open_page_xfer(&xfer, CR_FD_PAGEMAP, ctl->pid.virt);
266 [ + - ]: 919 : if (ret < 0)
267 : : goto out_pp;
268 : : }
269 : :
270 : : /*
271 : : * Step 1 -- generate the pagemap
272 : : */
273 : 3664 : args->off = 0;
274 [ + + ]: 159248 : list_for_each_entry(vma_area, &vma_area_list->h, list) {
275 : 155584 : u64 off = 0;
276 : : u64 *map;
277 : :
278 [ + + ]: 155584 : if (!privately_dump_vma(vma_area))
279 : 4184 : continue;
280 : :
281 : 151400 : map = pmc_get_map(&pmc, vma_area);
282 [ + - ]: 151400 : if (!map)
283 : : goto out_xfer;
284 : : again:
285 : 151400 : ret = generate_iovs(vma_area, pp, map, &off, xfer.parent);
286 [ - + ]: 151400 : if (ret == -EAGAIN) {
287 [ # # ]: 0 : BUG_ON(pp_ret);
288 : :
289 : 0 : ret = dump_pages(pp, ctl, args, &xfer);
290 [ # # ]: 0 : if (ret)
291 : : goto out_xfer;
292 : 0 : page_pipe_reinit(pp);
293 : 0 : goto again;
294 : : }
295 [ + - ]: 151400 : if (ret < 0)
296 : : goto out_xfer;
297 : : }
298 : :
299 [ + + ]: 3664 : ret = dump_pages(pp, ctl, args, pp_ret ? NULL : &xfer);
300 [ + - ]: 3664 : if (ret)
301 : : goto out_xfer;
302 : :
303 : 3664 : timing_stop(TIME_MEMDUMP);
304 : :
305 [ + + ]: 3664 : if (pp_ret)
306 : 2745 : *pp_ret = pp;
307 : :
308 : : /*
309 : : * Step 4 -- clean up
310 : : */
311 : :
312 : 3664 : ret = task_reset_dirty_track(ctl->pid.real);
313 : : out_xfer:
314 [ + + ]: 3664 : if (pp_ret == NULL)
315 : 919 : xfer.close(&xfer);
316 : : out_pp:
317 [ + + ]: 3664 : if (ret || !pp_ret)
318 : 919 : destroy_page_pipe(pp);
319 : : out:
320 : 3664 : pmc_fini(&pmc);
321 : 3664 : pr_info("----------------------------------------\n");
322 : 3664 : return ret;
323 : : }
324 : :
325 : 3664 : int parasite_dump_pages_seized(struct parasite_ctl *ctl,
326 : : struct vm_area_list *vma_area_list, struct page_pipe **pp)
327 : : {
328 : : int ret;
329 : : struct parasite_dump_pages_args *pargs;
330 : :
331 : 3664 : pargs = prep_dump_pages_args(ctl, vma_area_list);
332 : :
333 : : /*
334 : : * Add PROT_READ protection for all VMAs we're about to
335 : : * dump if they don't have one. Otherwise we'll not be
336 : : * able to read the memory contents.
337 : : *
338 : : * Afterwards -- reprotect memory back.
339 : : */
340 : :
341 : 3664 : pargs->add_prot = PROT_READ;
342 : 3664 : ret = parasite_execute_daemon(PARASITE_CMD_MPROTECT_VMAS, ctl);
343 [ - + ]: 3664 : if (ret) {
344 : 0 : pr_err("Can't dump unprotect vmas with parasite\n");
345 : 0 : return ret;
346 : : }
347 : :
348 : 3664 : ret = __parasite_dump_pages_seized(ctl, pargs, vma_area_list, pp);
349 [ - + ]: 3664 : if (ret)
350 : 0 : pr_err("Can't dump page with parasite\n");
351 : :
352 : 3664 : pargs->add_prot = 0;
353 [ - + ]: 3664 : if (parasite_execute_daemon(PARASITE_CMD_MPROTECT_VMAS, ctl)) {
354 : 0 : pr_err("Can't rollback unprotected vmas with parasite\n");
355 : : ret = -1;
356 : : }
357 : :
358 : 3664 : return ret;
359 : : }
360 : :
361 : : static inline int collect_filemap(struct vma_area *vma)
362 : : {
363 : : struct file_desc *fd;
364 : :
365 : 10456 : fd = collect_special_file(vma->e->shmid);
366 [ + - ]: 10456 : if (!fd)
367 : : return -1;
368 : :
369 : 10456 : vma->fd = fd;
370 : : return 0;
371 : : }
372 : :
373 : 1006 : int prepare_mm_pid(struct pstree_item *i)
374 : : {
375 : 1006 : pid_t pid = i->pid.virt;
376 : : int fd, ret = -1, vn = 0;
377 : : struct rst_info *ri = i->rst;
378 : :
379 : 1006 : fd = open_image(CR_FD_MM, O_RSTR | O_OPT, pid);
380 [ + + ]: 1006 : if (fd < 0) {
381 [ - + ]: 30 : if (fd == -ENOENT)
382 : : return 0;
383 : 0 : return -1;
384 : : }
385 : :
386 : 976 : ret = pb_read_one(fd, &ri->mm, PB_MM);
387 : 976 : close(fd);
388 [ + - ]: 976 : if (ret < 0)
389 : : return -1;
390 : :
391 [ + - ]: 976 : if (collect_special_file(ri->mm->exe_file_id) == NULL)
392 : : return -1;
393 : :
394 : 976 : pr_debug("Found %zd VMAs in image\n", ri->mm->n_vmas);
395 : : fd = -1;
396 [ - + ]: 976 : if (ri->mm->n_vmas == 0) {
397 : : /*
398 : : * Old image. Read VMAs from vma-.img
399 : : */
400 : 0 : fd = open_image(CR_FD_VMAS, O_RSTR, pid);
401 [ # # ]: 0 : if (fd < 0)
402 : : return -1;
403 : : }
404 : :
405 : :
406 [ + + ][ - + ]: 39220 : while (vn < ri->mm->n_vmas || fd >= 0) {
407 : : struct vma_area *vma;
408 : :
409 : : ret = -1;
410 : 38244 : vma = alloc_vma_area();
411 [ + - ]: 38244 : if (!vma)
412 : : break;
413 : :
414 : : ret = 0;
415 : 38244 : ri->vmas.nr++;
416 [ + - ]: 38244 : if (fd == -1)
417 : 38244 : vma->e = ri->mm->vmas[vn++];
418 : : else {
419 : 0 : ret = pb_read_one_eof(fd, &vma->e, PB_VMA);
420 [ # # ]: 0 : if (ret <= 0) {
421 [ # # ]: 0 : xfree(vma);
422 : 0 : close(fd);
423 : 0 : break;
424 : : }
425 : : }
426 : 38244 : list_add_tail(&vma->list, &ri->vmas.h);
427 : :
428 [ + + ][ + + ]: 38244 : if (vma_priv(vma->e)) {
429 : 37150 : ri->vmas.priv_size += vma_area_len(vma);
430 [ + + ]: 37150 : if (vma->e->flags & MAP_GROWSDOWN)
431 : 994 : ri->vmas.priv_size += PAGE_SIZE;
432 : : }
433 : :
434 : 38244 : pr_info("vma 0x%"PRIx64" 0x%"PRIx64"\n", vma->e->start, vma->e->end);
435 : :
436 [ + + ]: 38244 : if (vma_area_is(vma, VMA_ANON_SHARED) &&
437 : : !vma_area_is(vma, VMA_AREA_SYSVIPC))
438 : 76 : ret = collect_shmem(pid, vma->e);
439 [ + + ]: 38168 : else if (vma_area_is(vma, VMA_FILE_PRIVATE) ||
440 : : vma_area_is(vma, VMA_FILE_SHARED))
441 : : ret = collect_filemap(vma);
442 : : else
443 : : ret = 0;
444 [ + - ]: 39220 : if (ret)
445 : : break;
446 : : }
447 : :
448 : 976 : return ret;
449 : : }
450 : :
|