@@ -2472,6 +2472,47 @@ static inline MemOp devend_memop(enum device_endian end)
}
#endif
+/*
+ * Inhibit technologies that require discarding of pages in RAM blocks, e.g.,
+ * to manage the actual amount of memory consumed by the VM (then, the memory
+ * provided by RAM blocks might be bigger than the desired memory consumption).
+ * This *must* be set if:
+ * - Discarding parts of a RAM blocks does not result in the change being
+ * reflected in the VM and the pages getting freed.
+ * - All memory in RAM blocks is pinned or duplicated, invaldiating any previous
+ * discards blindly.
+ * - Discarding parts of a RAM blocks will result in integrity issues (e.g.,
+ * encrypted VMs).
+ * Technologies that only temporarily pin the current working set of a
+ * driver are fine, because we don't expect such pages to be discarded
+ * (esp. based on guest action like balloon inflation).
+ *
+ * This is *not* to be used to protect from concurrent discards (esp.,
+ * postcopy).
+ *
+ * Returns 0 if successful. Returns -EBUSY if a technology that relies on
+ * discards to work reliably is active.
+ */
+int ram_block_discard_disable(bool state);
+
+/*
+ * Inhibit technologies that disable discarding of pages in RAM blocks.
+ *
+ * Returns 0 if successful. Returns -EBUSY if discards are already set to
+ * broken.
+ */
+int ram_block_discard_require(bool state);
+
+/*
+ * Test if discarding of memory in ram blocks is disabled.
+ */
+bool ram_block_discard_is_disabled(void);
+
+/*
+ * Test if discarding of memory in ram blocks is required to work reliably.
+ */
+bool ram_block_discard_is_required(void);
+
#endif
#endif
@@ -40,7 +40,8 @@ static int balloon_inhibit_count;
bool qemu_balloon_is_inhibited(void)
{
- return atomic_read(&balloon_inhibit_count) > 0;
+ return atomic_read(&balloon_inhibit_count) > 0 ||
+ ram_block_discard_is_disabled();
}
void qemu_balloon_inhibit(bool state)
@@ -4115,4 +4115,56 @@ void mtree_print_dispatch(AddressSpaceDispatch *d, MemoryRegion *root)
}
}
+/*
+ * If positive, discarding RAM is disabled. If negative, discarding RAM is
+ * required to work and cannot be disabled.
+ */
+static int ram_block_discard_disabled;
+
+int ram_block_discard_disable(bool state)
+{
+ int old;
+
+ if (!state) {
+ atomic_dec(&ram_block_discard_disabled);
+ return 0;
+ }
+
+ do {
+ old = atomic_read(&ram_block_discard_disabled);
+ if (old < 0) {
+ return -EBUSY;
+ }
+ } while (atomic_cmpxchg(&ram_block_discard_disabled, old, old + 1) != old);
+ return 0;
+}
+
+int ram_block_discard_require(bool state)
+{
+ int old;
+
+ if (!state) {
+ atomic_inc(&ram_block_discard_disabled);
+ return 0;
+ }
+
+ do {
+ old = atomic_read(&ram_block_discard_disabled);
+ if (old > 0) {
+ return -EBUSY;
+ }
+ } while (atomic_cmpxchg(&ram_block_discard_disabled, old, old - 1) != old);
+ return 0;
+}
+
+bool ram_block_discard_is_disabled(void)
+{
+ return atomic_read(&ram_block_discard_disabled) > 0;
+}
+
+bool ram_block_discard_is_required(void)
+{
+ return atomic_read(&ram_block_discard_disabled) < 0;
+}
+
#endif