A guest that reassigns the BARs of several devices without turning
decoding off, as Linux does on arm64, routinely puts a BAR where another
device's BAR still is; that one moves away a moment later.
register_mem() reports success without registering anything when the
new range starts inside a registered one, and returns an error when it
overlaps one otherwise. Either way modify_bar_registration() never
tries again, and in the first case it even believes the BAR is
registered. The BAR then stays without a handler for good: its accesses
fall through to the PCI fallback handler, reads return all ones, and
for instance a virtio 1.0 driver waits forever for device_status to
read 0 after a reset.
The silent success dates from 028d9311cdfb (April 2013), which let the
guest reprogram BARs and made register_mem() look the base up first and
add the range only if nothing was found there. 6f051f0e5 (D60748,
October 2026) made a failed registration non-fatal and records it in
pcibar.registered; this change builds on that and registers such a BAR
once its range is free.
Make register_mem() fail with EEXIST in the first case too, and try the
unregistered BARs of all devices again whenever a BAR has moved or a
device's decoding has changed.
Fixes: 028d9311cdfb ("Improve PCI BAR emulation")
Signed-off-by: Wanpeng Qian <wanpengqian@gmail.com>
Sponsored by: keelos.dev