Skip to content

Commit 0c82f5e

Browse files
committed
CA-422282 Fix race condition about xenops cache
There is race condition about vm cache between pool_migrate_complete and VM event. In the cross-pool migration case, it is designed to create vm with power_state Halted in XAPI db. In pool_migrate_complete, add_caches create an empty xenops_chae for the VM, then refresh_vm compares the cache powerstate None with its real state Running to update the right powerstate to XAPI db. In the fail case, it is found that: -> VM event 1 update_vm -> pool_migrate_complete add_caches (cache power_state None) -> pool_migrate_complete refresh_vm -> VM event 1 update cache (cache power_state Running) -> VM event 2 update_vm (Running <-> Running, XAPI DB not update) When pool_migrate_complete add_caches, the cache update of previous VM event 1 breaks the design intention. This PR Add a new interface add_caches_and_refresh to make the procedure race-free. 1. Wait for barrier - ensure all in-flight events complete 2. Suppress + add_caches - prevent new events 3. Refresh Signed-off-by: Changlei Li <changlei.li@cloud.com>
1 parent 595e68a commit 0c82f5e

2 files changed

Lines changed: 13 additions & 2 deletions

File tree

ocaml/xapi/xapi_vm_migrate.ml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -492,8 +492,7 @@ let pool_migrate_complete ~__context ~vm ~host:_ =
492492
if Xapi_xenops.vm_exists_in_xenopsd queue_name dbg id then (
493493
remove_stale_pcis ~__context ~vm ;
494494
Xapi_xenops.set_resident_on ~__context ~self:vm ;
495-
Xapi_xenops.add_caches id ;
496-
Xapi_xenops.refresh_vm ~__context ~self:vm ;
495+
Xapi_xenops.add_caches_and_refresh queue_name dbg id ;
497496
Monitor_dbcalls_cache.clear_cache_for_vm ~vm_uuid:id
498497
) ;
499498
(* Reset the state, which will update allowed operations, clear reservations

ocaml/xapi/xapi_xenops.ml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1924,6 +1924,18 @@ let add_caches id =
19241924
Xenops_cache.register id
19251925
)
19261926

1927+
let add_caches_and_refresh queue_name dbg id =
1928+
(* Fix race condition with proper three-step approach:
1929+
Step 1: Wait for barrier - ensures all in-flight events complete
1930+
This prevents TOCTOU where an event passes the suppression check
1931+
but writes to cache after the wipe.
1932+
Step 2: Suppress + wipe - prevents new events during cache wipe
1933+
Step 3: Refresh (automatic) - with_suppressed cleanup calls refresh_vm
1934+
which generates fresh events and waits for barrier
1935+
*)
1936+
Events_from_xenopsd.wait queue_name dbg id () ;
1937+
Events_from_xenopsd.with_suppressed queue_name dbg id (fun () -> add_caches id)
1938+
19271939
let to_xenops_console_protocol =
19281940
let open Vm in
19291941
function `rfb -> Rfb | `vt100 -> Vt100 | `rdp -> Rfb

0 commit comments

Comments
 (0)