@@ -99,38 +99,61 @@ static inline bool __page_in_parent(bool dirty)
99
99
return opts .track_mem && opts .img_parent && !dirty ;
100
100
}
101
101
102
- bool should_dump_page (VmaEntry * vmae , u64 pme )
102
+ static bool should_dump_entire_vma (VmaEntry * vmae )
103
103
{
104
104
/*
105
105
* vDSO area must be always dumped because on restore
106
106
* we might need to generate a proxy.
107
107
*/
108
108
if (vma_entry_is (vmae , VMA_AREA_VDSO ))
109
109
return true;
110
- /*
111
- * In turn VVAR area is special and referenced from
112
- * vDSO area by IP addressing (at least on x86) thus
113
- * never ever dump its content but always use one provided
114
- * by the kernel on restore, ie runtime VVAR area must
115
- * be remapped into proper place..
116
- */
117
- if (vma_entry_is (vmae , VMA_AREA_VVAR ))
118
- return false;
119
-
120
- /*
121
- * Optimisation for private mapping pages, that haven't
122
- * yet being COW-ed
123
- */
124
- if (vma_entry_is (vmae , VMA_FILE_PRIVATE ) && (pme & PME_FILE ))
125
- return false;
126
110
if (vma_entry_is (vmae , VMA_AREA_AIORING ))
127
111
return true;
128
- if ((pme & (PME_PRESENT | PME_SWAP )) && !__page_is_zero (pme ))
129
- return true;
130
112
131
113
return false;
132
114
}
133
115
116
+ /*
117
+ * should_dump_page returns vaddr if an addressed page has to be dumped.
118
+ * Otherwise, it returns an address that has to be inspected next.
119
+ */
120
+ u64 should_dump_page (pmc_t * pmc , VmaEntry * vmae , u64 vaddr , bool * softdirty )
121
+ {
122
+ if (vaddr >= pmc -> end && pmc_fill (pmc , vaddr , vmae -> end ))
123
+ return -1 ;
124
+
125
+ if (pmc -> regs ) {
126
+ while (1 ) {
127
+ if (pmc -> regs_idx == pmc -> regs_len )
128
+ return pmc -> end ;
129
+ if (vaddr < pmc -> regs [pmc -> regs_idx ].end )
130
+ break ;
131
+ pmc -> regs_idx ++ ;
132
+ }
133
+ if (vaddr < pmc -> regs [pmc -> regs_idx ].start )
134
+ return pmc -> regs [pmc -> regs_idx ].start ;
135
+ if (softdirty )
136
+ * softdirty = pmc -> regs [pmc -> regs_idx ].categories & PAGE_IS_SOFT_DIRTY ;
137
+ return vaddr ;
138
+ } else {
139
+ u64 pme = pmc -> map [PAGE_PFN (vaddr - pmc -> start )];
140
+
141
+ /*
142
+ * Optimisation for private mapping pages, that haven't
143
+ * yet being COW-ed
144
+ */
145
+ if (vma_entry_is (vmae , VMA_FILE_PRIVATE ) && (pme & PME_FILE ))
146
+ return vaddr + PAGE_SIZE ;
147
+ if ((pme & (PME_PRESENT | PME_SWAP )) && !__page_is_zero (pme )) {
148
+ if (softdirty )
149
+ * softdirty = pme & PME_SOFT_DIRTY ;
150
+ return vaddr ;
151
+ }
152
+
153
+ return vaddr + PAGE_SIZE ;
154
+ }
155
+ }
156
+
134
157
bool page_is_zero (u64 pme )
135
158
{
136
159
return __page_is_zero (pme );
@@ -164,25 +187,30 @@ static bool is_stack(struct pstree_item *item, unsigned long vaddr)
164
187
* the memory contents is present in the parent image set.
165
188
*/
166
189
167
- static int generate_iovs (struct pstree_item * item , struct vma_area * vma , struct page_pipe * pp , u64 * map , u64 * off ,
190
+ static int generate_iovs (struct pstree_item * item , struct vma_area * vma , struct page_pipe * pp , pmc_t * pmc , u64 * pvaddr ,
168
191
bool has_parent )
169
192
{
170
- u64 * at = & map [PAGE_PFN (* off )];
171
- unsigned long pfn , nr_to_scan ;
193
+ unsigned long nr_scanned ;
172
194
unsigned long pages [3 ] = {};
195
+ unsigned long vaddr ;
196
+ bool dump_all_pages ;
173
197
int ret = 0 ;
174
198
175
- nr_to_scan = ( vma_area_len ( vma ) - * off ) / PAGE_SIZE ;
199
+ dump_all_pages = should_dump_entire_vma ( vma -> e ) ;
176
200
177
- for ( pfn = 0 ; pfn < nr_to_scan ; pfn ++ ) {
178
- unsigned long vaddr ;
201
+ nr_scanned = 0 ;
202
+ for ( vaddr = * pvaddr ; vaddr < vma -> e -> end ; vaddr += PAGE_SIZE , nr_scanned ++ ) {
179
203
unsigned int ppb_flags = 0 ;
204
+ bool softdirty = false;
205
+ u64 next ;
180
206
int st ;
181
207
182
- if (!should_dump_page (vma -> e , at [pfn ]))
208
+ /* If dump_all_pages is true, should_dump_page is called to get pme. */
209
+ next = should_dump_page (pmc , vma -> e , vaddr , & softdirty );
210
+ if (!dump_all_pages && next != vaddr ) {
211
+ vaddr = next - PAGE_SIZE ;
183
212
continue ;
184
-
185
- vaddr = vma -> e -> start + * off + pfn * PAGE_SIZE ;
213
+ }
186
214
187
215
if (vma_entry_can_be_lazy (vma -> e ) && !is_stack (item , vaddr ))
188
216
ppb_flags |= PPB_LAZY ;
@@ -194,7 +222,7 @@ static int generate_iovs(struct pstree_item *item, struct vma_area *vma, struct
194
222
* page. The latter would be checked in page-xfer.
195
223
*/
196
224
197
- if (has_parent && page_in_parent (at [ pfn ] & PME_SOFT_DIRTY )) {
225
+ if (has_parent && page_in_parent (softdirty )) {
198
226
ret = page_pipe_add_hole (pp , vaddr , PP_HOLE_PARENT );
199
227
st = 0 ;
200
228
} else {
@@ -214,9 +242,8 @@ static int generate_iovs(struct pstree_item *item, struct vma_area *vma, struct
214
242
pages [st ]++ ;
215
243
}
216
244
217
- * off += pfn * PAGE_SIZE ;
218
-
219
- cnt_add (CNT_PAGES_SCANNED , nr_to_scan );
245
+ * pvaddr = vaddr ;
246
+ cnt_add (CNT_PAGES_SCANNED , nr_scanned );
220
247
cnt_add (CNT_PAGES_SKIPPED_PARENT , pages [0 ]);
221
248
cnt_add (CNT_PAGES_LAZY , pages [1 ]);
222
249
cnt_add (CNT_PAGES_WRITTEN , pages [2 ]);
@@ -356,12 +383,20 @@ static int generate_vma_iovs(struct pstree_item *item, struct vma_area *vma, str
356
383
struct page_xfer * xfer , struct parasite_dump_pages_args * args , struct parasite_ctl * ctl ,
357
384
pmc_t * pmc , bool has_parent , bool pre_dump , int parent_predump_mode )
358
385
{
359
- u64 off = 0 ;
360
- u64 * map ;
386
+ u64 vaddr ;
361
387
int ret ;
362
388
363
389
if (!vma_area_is_private (vma , kdat .task_size ) && !vma_area_is (vma , VMA_ANON_SHARED ))
364
390
return 0 ;
391
+ /*
392
+ * In turn VVAR area is special and referenced from
393
+ * vDSO area by IP addressing (at least on x86) thus
394
+ * never ever dump its content but always use one provided
395
+ * by the kernel on restore, ie runtime VVAR area must
396
+ * be remapped into proper place..
397
+ */
398
+ if (vma_entry_is (vma -> e , VMA_AREA_VVAR ))
399
+ return 0 ;
365
400
366
401
/*
367
402
* To facilitate any combination of pre-dump modes to run after
@@ -421,15 +456,14 @@ static int generate_vma_iovs(struct pstree_item *item, struct vma_area *vma, str
421
456
has_parent = false;
422
457
}
423
458
424
- map = pmc_get_map (pmc , vma );
425
- if (!map )
459
+ if (pmc_get_map (pmc , vma ))
426
460
return -1 ;
427
461
428
462
if (vma_area_is (vma , VMA_ANON_SHARED ))
429
- return add_shmem_area (item -> pid -> real , vma -> e , map );
430
-
463
+ return add_shmem_area (item -> pid -> real , vma -> e , pmc );
464
+ vaddr = vma -> e -> start ;
431
465
again :
432
- ret = generate_iovs (item , vma , pp , map , & off , has_parent );
466
+ ret = generate_iovs (item , vma , pp , pmc , & vaddr , has_parent );
433
467
if (ret == - EAGAIN ) {
434
468
BUG_ON (!(pp -> flags & PP_CHUNK_MODE ));
435
469
0 commit comments