bql: check that the BQL is not dropped within marked sections

The Big QEMU Lock (BQL) is used to provide interior mutability to Rust
code.  While BqlCell performs indivisible accesses, an equivalent of
RefCell will allow the borrower to hold to the interior content for a
long time.  If the BQL is dropped, another thread could come and mutate
the data from C code (Rust code would panic on borrow_mut() instead).
In order to prevent this, add a new BQL primitive that can mark
BQL-atomic sections and aborts if the BQL is dropped within them.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2024-11-06 08:59:07 +01:00
parent 281305d3e0
commit 37fb26601d
3 changed files with 45 additions and 0 deletions

View file

@ -514,6 +514,20 @@ bool qemu_in_vcpu_thread(void)
QEMU_DEFINE_STATIC_CO_TLS(bool, bql_locked)
static uint32_t bql_unlock_blocked;
void bql_block_unlock(bool increase)
{
uint32_t new_value;
assert(bql_locked());
/* check for overflow! */
new_value = bql_unlock_blocked + increase - !increase;
assert((new_value > bql_unlock_blocked) == increase);
bql_unlock_blocked = new_value;
}
bool bql_locked(void)
{
return get_bql_locked();
@ -540,6 +554,7 @@ void bql_lock_impl(const char *file, int line)
void bql_unlock(void)
{
g_assert(bql_locked());
g_assert(!bql_unlock_blocked);
set_bql_locked(false);
qemu_mutex_unlock(&bql);
}