27
return rdsc->is_populated(rds, section);
28
}
29
30
-static int ram_discard_source_replay_populated(const RamDiscardSource *rds,
31
- const MemoryRegionSection *section,
32
- ReplayRamDiscardState replay_fn,
33
- void *opaque)
30
+/*
31
+ * Iterate the section at source granularity, aggregating consecutive chunks
32
+ * with matching populated state, and call replay_fn for each run.
33
+ */
34
+static int replay_by_populated_state(const RamDiscardManager *rdm,
35
+ const MemoryRegionSection *section,
36
+ bool replay_populated,
37
+ ReplayRamDiscardState replay_fn,
38
+ void *opaque)
39
{
35
- RamDiscardSourceClass *rdsc = RAM_DISCARD_SOURCE_GET_CLASS(rds);
40
+ uint64_t granularity, offset, size, end, pos, run_start = 0;
41
+ bool in_run = false;
42
+ int ret = 0;
43
37
- g_assert(rdsc->replay_populated);
38
- return rdsc->replay_populated(rds, section, replay_fn, opaque);
39
-}
44
+ granularity = ram_discard_source_get_min_granularity(rdm->rds, rdm->mr);
45
+ offset = section->offset_within_region;
46
+ size = int128_get64(section->size);
47
+ end = offset + size;
48
+
49
+ /* Align iteration to granularity boundaries */
50
+ pos = QEMU_ALIGN_DOWN(offset, granularity);
51
+
52
+ for (; pos < end; pos += granularity) {
53
+ MemoryRegionSection chunk = {
54
+ .mr = section->mr,
55
+ .offset_within_region = pos,
56
+ .size = int128_make64(granularity),
57
+ };
58
+ bool populated = ram_discard_source_is_populated(rdm->rds, &chunk);
59
+
60
+ if (populated == replay_populated) {
61
+ if (!in_run) {
62
+ run_start = pos;
63
+ in_run = true;
64
+ }
65
+ } else if (in_run) {
66
+ MemoryRegionSection tmp = *section;
67
+
68
+ if (memory_region_section_intersect_range(&tmp, run_start,
69
+ pos - run_start)) {
70
+ ret = replay_fn(&tmp, opaque);
71
+ if (ret) {
72
+ return ret;
73
+ }
74
+ }
75
+ in_run = false;
76
+ }
77
+ }
78
41
-static int ram_discard_source_replay_discarded(const RamDiscardSource *rds,
42
- const MemoryRegionSection *section,
43
- ReplayRamDiscardState replay_fn,
44
- void *opaque)
45
-{
46
- RamDiscardSourceClass *rdsc = RAM_DISCARD_SOURCE_GET_CLASS(rds);
79
+ if (in_run) {
80
+ MemoryRegionSection tmp = *section;
81
48
- g_assert(rdsc->replay_discarded);
49
- return rdsc->replay_discarded(rds, section, replay_fn, opaque);
82
+ if (memory_region_section_intersect_range(&tmp, run_start,
83
+ pos - run_start)) {
84
+ ret = replay_fn(&tmp, opaque);
85
+ }
86
+ }
87
+
88
+ return ret;
89
}
90
91
RamDiscardManager *ram_discard_manager_new(MemoryRegion *mr,
117
ReplayRamDiscardState replay_fn,
118
void *opaque)
119
{
81
- return ram_discard_source_replay_populated(rdm->rds, section,
82
- replay_fn, opaque);
120
+ return replay_by_populated_state(rdm, section, true, replay_fn, opaque);
121
}
122
123
int ram_discard_manager_replay_discarded(const RamDiscardManager *rdm,
125
ReplayRamDiscardState replay_fn,
126
void *opaque)
127
{
90
- return ram_discard_source_replay_discarded(rdm->rds, section,
91
- replay_fn, opaque);
128
+ return replay_by_populated_state(rdm, section, false, replay_fn, opaque);
129
}
130
131
static void ram_discard_manager_initfn(Object *obj)
219
rdl->section = memory_region_section_new_copy(section);
220
QLIST_INSERT_HEAD(&rdm->rdl_list, rdl, next);
221
185
- ret = ram_discard_source_replay_populated(rdm->rds, rdl->section,
186
- rdm_populate_cb, rdl);
222
+ ret = ram_discard_manager_replay_populated(rdm, rdl->section,
223
+ rdm_populate_cb, rdl);
224
if (ret) {
225
error_report("%s: Replaying populated ranges failed: %s", __func__,
226
strerror(-ret));
245
int ret = 0;
246
247
QLIST_FOREACH(rdl, &rdm->rdl_list, next) {
211
- ret = ram_discard_source_replay_populated(rdm->rds, rdl->section,
212
- rdm_populate_cb, rdl);
248
+ ret = ram_discard_manager_replay_populated(rdm, rdl->section,
249
+ rdm_populate_cb, rdl);
250
if (ret) {
251
break;
252
}