Skip to content

Commit aa2aa6e

Browse files
gthvn1glehmann
authored andcommitted
Check that there are no changes during SR.scan
Currently, we are only checking that no VDIs have been removed during the SR scan performed by the SM plugin. However, there are situations where a VDI has been added, and if this VDI is not present in the list obtained from SR.scan, it will be forgotten. The checks only prevent this in the case where the VDI was added during the scan. There is still a TOCTOU situation if the issue happens after the scan, and there is room for that. Signed-off-by: Guillaume <[email protected]>
1 parent 5881065 commit aa2aa6e

File tree

1 file changed

+23
-14
lines changed

1 file changed

+23
-14
lines changed

ocaml/xapi/xapi_sr.ml

+23-14
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,11 @@ let update_vdis ~__context ~sr db_vdis vdi_infos =
757757

758758
(* Perform a scan of this locally-attached SR *)
759759
let scan ~__context ~sr =
760+
let module RefSet = Set.Make (struct
761+
type t = [`VDI] Ref.t
762+
763+
let compare = Ref.compare
764+
end) in
760765
let open Storage_access in
761766
let task = Context.get_task_id __context in
762767
let module C = Storage_interface.StorageAPI (Idl.Exn.GenClient (struct
@@ -781,9 +786,21 @@ let scan ~__context ~sr =
781786
(* It is sufficient to just compare the refs in two db_vdis, as this
782787
is what update_vdis uses to determine what to delete *)
783788
let vdis_ref_equal db_vdi1 db_vdi2 =
784-
Listext.List.set_difference (List.map fst db_vdi1)
785-
(List.map fst db_vdi2)
786-
= []
789+
let refs1 = RefSet.of_list (List.map fst db_vdi1) in
790+
let refs2 = RefSet.of_list (List.map fst db_vdi2) in
791+
if RefSet.equal refs1 refs2 then
792+
true
793+
else
794+
let log_diff label a b =
795+
RefSet.diff a b
796+
|> RefSet.elements
797+
|> List.map Ref.string_of
798+
|> String.concat " "
799+
|> debug "%s: VDIs %s during scan: %s" __FUNCTION__ label
800+
in
801+
log_diff "removed" refs1 refs2 ;
802+
log_diff "added" refs2 refs1 ;
803+
false
787804
in
788805
let db_vdis_before = find_vdis () in
789806
let vs, sr_info =
@@ -793,24 +810,16 @@ let scan ~__context ~sr =
793810
let db_vdis_after = find_vdis () in
794811
if limit > 0 && not (vdis_ref_equal db_vdis_before db_vdis_after)
795812
then (
796-
debug
797-
"%s detected db change while scanning, before scan vdis %s, \
798-
after scan vdis %s, retry limit left %d"
799-
__FUNCTION__
800-
(List.map (fun (_, v) -> v.vDI_uuid) db_vdis_before
801-
|> String.concat ","
802-
)
803-
(List.map (fun (_, v) -> v.vDI_uuid) db_vdis_after
804-
|> String.concat ","
805-
)
806-
limit ;
813+
debug "%s detected db change while scanning, retry limit left %d"
814+
__FUNCTION__ limit ;
807815
(scan_rec [@tailcall]) (limit - 1)
808816
) else if limit = 0 then
809817
raise
810818
(Api_errors.Server_error
811819
(Api_errors.internal_error, ["SR.scan retry limit exceeded"])
812820
)
813821
else (
822+
debug "%s no change detected, updating VDIs" __FUNCTION__ ;
814823
update_vdis ~__context ~sr db_vdis_after vs ;
815824
let virtual_allocation =
816825
List.fold_left

0 commit comments

Comments
 (0)