@@ -1494,6 +1494,111 @@ let string_of_exn = function
14941494 | e ->
14951495 Printexc. to_string e
14961496
1497+ module Events_from_xenopsd = struct
1498+ type t = {mutable finished : bool ; m : Mutex .t ; c : Condition .t }
1499+
1500+ let make () = {finished= false ; m= Mutex. create () ; c= Condition. create () }
1501+
1502+ let active = Hashtbl. create 10
1503+
1504+ let active_m = Mutex. create ()
1505+
1506+ let register =
1507+ let counter = ref 0 in
1508+ fun t ->
1509+ with_lock active_m (fun () ->
1510+ let id = ! counter in
1511+ incr counter ;
1512+ Hashtbl. replace active id t ;
1513+ id
1514+ )
1515+
1516+ let wait queue_name dbg vm_id () =
1517+ let module Client = (val make_client queue_name : XENOPS ) in
1518+ let t = make () in
1519+ let id = register t in
1520+ Debug_info. with_dbg
1521+ ~attributes:
1522+ [
1523+ (" messaging.operation.name" , " subscribe" )
1524+ ; (" messaging.system" , " event" )
1525+ ; (" messaging.destination.subscription.name" , vm_id)
1526+ ; (" messaging.message.id" , string_of_int id)
1527+ ]
1528+ ~name: (" subscribe" ^ " " ^ queue_name)
1529+ ~dbg
1530+ @@ fun di ->
1531+ let dbg = Debug_info. to_string di in
1532+ debug " Client.UPDATES.inject_barrier %d" id ;
1533+ Client.UPDATES. inject_barrier dbg vm_id id ;
1534+ with_lock t.m (fun () ->
1535+ while not t.finished do
1536+ Condition. wait t.c t.m
1537+ done
1538+ )
1539+
1540+ let wakeup queue_name dbg id =
1541+ Debug_info. with_dbg
1542+ ~attributes:
1543+ [
1544+ (" messaging.operation.name" , " settle" )
1545+ ; (" messaging.system" , " event" )
1546+ ; (" messaging.message.id" , string_of_int id)
1547+ ]
1548+ ~name: (" settle" ^ " " ^ queue_name)
1549+ ~dbg
1550+ @@ fun di ->
1551+ let dbg = Debug_info. to_string di in
1552+ let module Client = (val make_client queue_name : XENOPS ) in
1553+ Client.UPDATES. remove_barrier dbg id ;
1554+ let t =
1555+ with_lock active_m @@ fun () ->
1556+ match Hashtbl. find_opt active id with
1557+ | Some t ->
1558+ Hashtbl. remove active id ; Some t
1559+ | None ->
1560+ warn " Events_from_xenopsd.wakeup: unknown id %d" id ;
1561+ None
1562+ in
1563+ Option. iter
1564+ (fun t ->
1565+ with_lock t.m @@ fun () ->
1566+ t.finished < - true ;
1567+ Condition. signal t.c
1568+ )
1569+ t
1570+
1571+ let events_suppressed_on = Hashtbl. create 10
1572+
1573+ let events_suppressed_on_m = Mutex. create ()
1574+
1575+ let events_suppressed_on_c = Condition. create ()
1576+
1577+ let are_suppressed vm = Hashtbl. mem events_suppressed_on vm
1578+
1579+ let with_suppressed queue_name dbg vm_id f =
1580+ debug " suppressing xenops events on VM: %s" vm_id ;
1581+ let module Client = (val make_client queue_name : XENOPS ) in
1582+ with_lock events_suppressed_on_m (fun () ->
1583+ Hashtbl. add events_suppressed_on vm_id ()
1584+ ) ;
1585+ finally f (fun () ->
1586+ with_lock events_suppressed_on_m (fun () ->
1587+ Hashtbl. remove events_suppressed_on vm_id ;
1588+ if not (Hashtbl. mem events_suppressed_on vm_id) then (
1589+ debug " re-enabled xenops events on VM: %s; refreshing VM" vm_id ;
1590+ Client.UPDATES. refresh_vm dbg vm_id ;
1591+ wait queue_name dbg vm_id () ;
1592+ Condition. broadcast events_suppressed_on_c
1593+ ) else
1594+ while are_suppressed vm_id do
1595+ debug " waiting for events to become re-enabled" ;
1596+ Condition. wait events_suppressed_on_c events_suppressed_on_m
1597+ done
1598+ )
1599+ )
1600+ end
1601+
14971602(* Serialise updates to the metadata caches *)
14981603let metadata_m = Mutex. create ()
14991604
@@ -1819,6 +1924,18 @@ let add_caches id =
18191924 Xenops_cache. register id
18201925 )
18211926
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+
18221939let to_xenops_console_protocol =
18231940 let open Vm in
18241941 function `rfb -> Rfb | `vt100 -> Vt100 | `rdp -> Rfb
@@ -1842,111 +1959,6 @@ let to_xenapi_console_protocol =
18421959let trigger_xenapi_reregister =
18431960 ref (fun () -> debug " No xapi event thread to wake up" )
18441961
1845- module Events_from_xenopsd = struct
1846- type t = {mutable finished : bool ; m : Mutex .t ; c : Condition .t }
1847-
1848- let make () = {finished= false ; m= Mutex. create () ; c= Condition. create () }
1849-
1850- let active = Hashtbl. create 10
1851-
1852- let active_m = Mutex. create ()
1853-
1854- let register =
1855- let counter = ref 0 in
1856- fun t ->
1857- with_lock active_m (fun () ->
1858- let id = ! counter in
1859- incr counter ;
1860- Hashtbl. replace active id t ;
1861- id
1862- )
1863-
1864- let wait queue_name dbg vm_id () =
1865- let module Client = (val make_client queue_name : XENOPS ) in
1866- let t = make () in
1867- let id = register t in
1868- Debug_info. with_dbg
1869- ~attributes:
1870- [
1871- (" messaging.operation.name" , " subscribe" )
1872- ; (" messaging.system" , " event" )
1873- ; (" messaging.destination.subscription.name" , vm_id)
1874- ; (" messaging.message.id" , string_of_int id)
1875- ]
1876- ~name: (" subscribe" ^ " " ^ queue_name)
1877- ~dbg
1878- @@ fun di ->
1879- let dbg = Debug_info. to_string di in
1880- debug " Client.UPDATES.inject_barrier %d" id ;
1881- Client.UPDATES. inject_barrier dbg vm_id id ;
1882- with_lock t.m (fun () ->
1883- while not t.finished do
1884- Condition. wait t.c t.m
1885- done
1886- )
1887-
1888- let wakeup queue_name dbg id =
1889- Debug_info. with_dbg
1890- ~attributes:
1891- [
1892- (" messaging.operation.name" , " settle" )
1893- ; (" messaging.system" , " event" )
1894- ; (" messaging.message.id" , string_of_int id)
1895- ]
1896- ~name: (" settle" ^ " " ^ queue_name)
1897- ~dbg
1898- @@ fun di ->
1899- let dbg = Debug_info. to_string di in
1900- let module Client = (val make_client queue_name : XENOPS ) in
1901- Client.UPDATES. remove_barrier dbg id ;
1902- let t =
1903- with_lock active_m @@ fun () ->
1904- match Hashtbl. find_opt active id with
1905- | Some t ->
1906- Hashtbl. remove active id ; Some t
1907- | None ->
1908- warn " Events_from_xenopsd.wakeup: unknown id %d" id ;
1909- None
1910- in
1911- Option. iter
1912- (fun t ->
1913- with_lock t.m @@ fun () ->
1914- t.finished < - true ;
1915- Condition. signal t.c
1916- )
1917- t
1918-
1919- let events_suppressed_on = Hashtbl. create 10
1920-
1921- let events_suppressed_on_m = Mutex. create ()
1922-
1923- let events_suppressed_on_c = Condition. create ()
1924-
1925- let are_suppressed vm = Hashtbl. mem events_suppressed_on vm
1926-
1927- let with_suppressed queue_name dbg vm_id f =
1928- debug " suppressing xenops events on VM: %s" vm_id ;
1929- let module Client = (val make_client queue_name : XENOPS ) in
1930- with_lock events_suppressed_on_m (fun () ->
1931- Hashtbl. add events_suppressed_on vm_id ()
1932- ) ;
1933- finally f (fun () ->
1934- with_lock events_suppressed_on_m (fun () ->
1935- Hashtbl. remove events_suppressed_on vm_id ;
1936- if not (Hashtbl. mem events_suppressed_on vm_id) then (
1937- debug " re-enabled xenops events on VM: %s; refreshing VM" vm_id ;
1938- Client.UPDATES. refresh_vm dbg vm_id ;
1939- wait queue_name dbg vm_id () ;
1940- Condition. broadcast events_suppressed_on_c
1941- ) else
1942- while are_suppressed vm_id do
1943- debug " waiting for events to become re-enabled" ;
1944- Condition. wait events_suppressed_on_c events_suppressed_on_m
1945- done
1946- )
1947- )
1948- end
1949-
19501962let update_vm_internal ~__context ~id ~self ~previous ~info ~localhost =
19511963 debug " xenopsd event: processing event for VM %s" id ;
19521964 if info = None then
0 commit comments