I think we need a memory_region_transaction_commit_force() to force
commit
some transactions when load vmstate. This function is designed like this:
/*
* memory_region_transaction_commit_force() is desgined to
* force the mr transaction to be commited in the process
* of loading vmstate.
*/
void memory_region_transaction_commit_force(void)
{
AddressSpace *as;
unsigned int memory_region_transaction_depth_copy =
memory_region_transaction_depth;
/*
* Temporarily replace memory_region_transaction_depth with 0 to
prevent
* memory_region_transaction_commit_force() and
address_space_to_flatview()
* call each other recursively.
*/
memory_region_transaction_depth = 0;
assert(qemu_mutex_iothread_locked());
if (memory_region_update_pending) {
flatviews_reset();
MEMORY_LISTENER_CALL_GLOBAL(begin, Forward);
QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
address_space_set_flatview(as);
address_space_update_ioeventfds(as);
}
memory_region_update_pending = false;
ioeventfd_update_pending = false;
MEMORY_LISTENER_CALL_GLOBAL(commit, Forward);
} else if (ioeventfd_update_pending) {
QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
address_space_update_ioeventfds(as);
}
ioeventfd_update_pending = false;
}
/* recover memory_region_transaction_depth */
memory_region_transaction_depth =
memory_region_transaction_depth_copy;
}
Now there are two options to use this function:
1. call it in address_space_to_flatview():
static inline FlatView *address_space_to_flatview(AddressSpace *as)
{
/*
* Before using any flatview, check whether we're during a memory
* region transaction. If so, force commit the memory region
transaction.
*/
if (memory_region_transaction_in_progress())
memory_region_transaction_commit_force();
return qatomic_rcu_read(&as->current_map);
}
2. call it before each post_load()
I prefer to use the former one, it is more general than the latter.
And with this function, the sanity check is not necessary any more.
Although we may inevitably call memory_region_transaction_commit_force()
several times, in my actual test, the number of calls to
memory_region_transaction_commit_force() is still insignificant compared
with the number of calls to memory_region_transaction_commit() before
optimization. As a result, This code won't affect the optimization
effect,
but it can ensure reliability.