@@ -3088,6 +3088,15 @@ int kvm_convert_memory(hwaddr start, hwaddr size, bool to_private)
addr = memory_region_get_ram_ptr(mr) + section.offset_within_region;
rb = qemu_ram_block_from_host(addr, false, &offset);
+ ret = private_shared_manager_state_change(PRIVATE_SHARED_MANAGER(mr->gsm),
+ offset, size, to_private);
+ if (ret) {
+ error_report("Failed to notify the listener the state change of "
+ "(0x%"HWADDR_PRIx" + 0x%"HWADDR_PRIx") to %s",
+ start, size, to_private ? "private" : "shared");
+ goto out_unref;
+ }
+
if (to_private) {
if (rb->page_size != qemu_real_host_page_size()) {
/*
@@ -46,6 +46,7 @@ struct RAMBlock {
int fd;
uint64_t fd_offset;
int guest_memfd;
+ RamBlockAttribute *ram_block_attribute;
size_t page_size;
/* dirty bitmap used during migration */
unsigned long *bmap;
@@ -1885,6 +1885,20 @@ static void ram_block_add(RAMBlock *new_block, Error **errp)
qemu_mutex_unlock_ramlist();
goto out_free;
}
+
+ new_block->ram_block_attribute = RAM_BLOCK_ATTRIBUTE(object_new(TYPE_RAM_BLOCK_ATTRIBUTE));
+ if (ram_block_attribute_realize(new_block->ram_block_attribute, new_block->mr)) {
+ error_setg(errp, "Failed to realize ram block attribute");
+ /*
+ * The error path could be unified if the rest of ram_block_add() ever
+ * develops a need to check for errors.
+ */
+ object_unref(OBJECT(new_block->ram_block_attribute));
+ close(new_block->guest_memfd);
+ ram_block_discard_require(false);
+ qemu_mutex_unlock_ramlist();
+ goto out_free;
+ }
}
ram_size = (new_block->offset + new_block->max_length) >> TARGET_PAGE_BITS;
@@ -2138,6 +2152,8 @@ static void reclaim_ramblock(RAMBlock *block)
}
if (block->guest_memfd >= 0) {
+ ram_block_attribute_unrealize(block->ram_block_attribute);
+ object_unref(OBJECT(block->ram_block_attribute));
close(block->guest_memfd);
ram_block_discard_require(false);
}
A new field, ram_block_attribute, is introduced in RAMBlock to link to a RamBlockAttribute object. This change centralizes all guest_memfd state information (such as fd and shared_bitmap) within a RAMBlock, simplifying management. The realize()/unrealized() helpers are used to initialize/uninitialize the RamBlockAttribute object. The object is registered/unregistered in the target RAMBlock's MemoryRegion when creating guest_memfd. Additionally, use the private_shared_manager_state_change() helper to notify the registered PrivateSharedListener of these changes. Signed-off-by: Chenyi Qiang <chenyi.qiang@intel.com> --- Changes in v4: - Remove the replay operations for attribute changes which will be handled in a listener in following patches. - Add some comment in the error path of realize() to remind the future development of the unified error path. Changes in v3: - Use ram_discard_manager_reply_populated/discarded() to set the memory attribute and add the undo support if state_change() failed. - Didn't add Reviewed-by from Alexey due to the new changes in this commit. Changes in v2: - Introduce a new field memory_attribute_manager in RAMBlock. - Move the state_change() handling during page conversion in this patch. - Undo what we did if it fails to set. - Change the order of close(guest_memfd) and memory_attribute_manager cleanup. --- accel/kvm/kvm-all.c | 9 +++++++++ include/exec/ramblock.h | 1 + system/physmem.c | 16 ++++++++++++++++ 3 files changed, 26 insertions(+)