Skip to content

Commit 111f83e

Browse files
authored
Check that suspend SR has enough space to save VM state (#6847)
This patch adds a helper to compute the free space on a SR. It is used to check that the suspend SR has enough space when creating a snapshot with memory. If there is not enough space, SR_SUSPEND_SPACE_INSUFFICIENT is raised. This is a backport of #6838
2 parents 80bb1fa + 9402e88 commit 111f83e

File tree

5 files changed

+51
-25
lines changed

5 files changed

+51
-25
lines changed

ocaml/idl/datamodel_errors.ml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,6 +1116,11 @@ let _ =
11161116
"The source SR does not have sufficient temporary space available to \
11171117
proceed the operation."
11181118
() ;
1119+
error Api_errors.sr_suspend_space_insufficient ["sr"]
1120+
~doc:
1121+
"The suspend SR does not have sufficient free space to store the VM \
1122+
suspend image required to complete a snapshot with memory."
1123+
() ;
11191124
error Api_errors.pbd_exists ["sr"; "host"; "pbd"]
11201125
~doc:"A PBD already exists connecting the SR to the server." () ;
11211126
error Api_errors.sr_has_pbd ["sr"]

ocaml/xapi-consts/api_errors.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,8 @@ let sr_full = add_error "SR_FULL"
501501

502502
let sr_source_space_insufficient = add_error "SR_SOURCE_SPACE_INSUFFICIENT"
503503

504+
let sr_suspend_space_insufficient = add_error "SR_SUSPEND_SPACE_INSUFFICIENT"
505+
504506
let sr_has_pbd = add_error "SR_HAS_PBD"
505507

506508
let sr_requires_upgrade = add_error "SR_REQUIRES_UPGRADE"

ocaml/xapi/helpers.ml

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,32 +1127,51 @@ let check_sr_exists_for_host ~__context ~self ~host =
11271127
else
11281128
None
11291129

1130+
(* Returns the amount of free space for a given SR *)
1131+
let get_sr_free_space ~__context ~sr =
1132+
let size = Db.SR.get_physical_size ~__context ~self:sr in
1133+
let utilisation = Db.SR.get_physical_utilisation ~__context ~self:sr in
1134+
Int64.sub size utilisation
1135+
11301136
(* Returns an SR suitable for suspending this VM *)
1131-
let choose_suspend_sr ~__context ~vm =
1137+
let choose_suspend_sr ~__context ~vm ~required_space =
11321138
(* If the VM.suspend_SR exists, use that. If it fails, try the Pool.suspend_image_SR. *)
11331139
(* If that fails, try the Host.suspend_image_SR. *)
11341140
let vm_sr = Db.VM.get_suspend_SR ~__context ~self:vm in
11351141
let pool = get_pool ~__context in
11361142
let pool_sr = Db.Pool.get_suspend_image_SR ~__context ~self:pool in
11371143
let resident_on = Db.VM.get_resident_on ~__context ~self:vm in
11381144
let host_sr = Db.Host.get_suspend_image_sr ~__context ~self:resident_on in
1139-
match
1140-
( check_sr_exists_for_host ~__context ~self:vm_sr ~host:resident_on
1141-
, check_sr_exists_for_host ~__context ~self:pool_sr ~host:resident_on
1142-
, check_sr_exists_for_host ~__context ~self:host_sr ~host:resident_on
1143-
)
1144-
with
1145-
| Some x, _, _ ->
1146-
x
1147-
| _, Some x, _ ->
1148-
x
1149-
| _, _, Some x ->
1150-
x
1151-
| None, None, None ->
1152-
raise
1153-
(Api_errors.Server_error
1154-
(Api_errors.vm_no_suspend_sr, [Ref.string_of vm])
1155-
)
1145+
let sr =
1146+
match
1147+
( check_sr_exists_for_host ~__context ~self:vm_sr ~host:resident_on
1148+
, check_sr_exists_for_host ~__context ~self:pool_sr ~host:resident_on
1149+
, check_sr_exists_for_host ~__context ~self:host_sr ~host:resident_on
1150+
)
1151+
with
1152+
| Some x, _, _ ->
1153+
x
1154+
| _, Some x, _ ->
1155+
x
1156+
| _, _, Some x ->
1157+
x
1158+
| None, None, None ->
1159+
raise
1160+
(Api_errors.Server_error
1161+
(Api_errors.vm_no_suspend_sr, [Ref.string_of vm])
1162+
)
1163+
in
1164+
let free_space = get_sr_free_space ~__context ~sr in
1165+
if free_space < required_space then (
1166+
let sr_str = Ref.string_of sr in
1167+
error "%s: SR %s free=%Ld needed=%Ld" __FUNCTION__ sr_str free_space
1168+
required_space ;
1169+
raise
1170+
(Api_errors.Server_error
1171+
(Api_errors.sr_suspend_space_insufficient, [sr_str])
1172+
)
1173+
) else
1174+
sr
11561175

11571176
(* return the operations filtered for cancels functions *)
11581177
let cancel_tasks ~__context ~ops ~all_tasks_in_db

ocaml/xapi/xapi_xenops.ml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3994,7 +3994,10 @@ let suspend ~__context ~self =
39943994
in
39953995
Int64.(ram |> add vgpu |> add 104857600L)
39963996
in
3997-
let suspend_SR = Helpers.choose_suspend_sr ~__context ~vm:self in
3997+
let suspend_SR =
3998+
Helpers.choose_suspend_sr ~__context ~vm:self
3999+
~required_space:space_needed
4000+
in
39984001
let sm_config =
39994002
[
40004003
(Constants._sm_vm_hint, id)

ocaml/xapi/xha_statefile.ml

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,11 @@ let ha_fits_sr ~__context ~what ~sr ~typ ~minimum_size =
5858
| [] ->
5959
debug "no suitable existing %s found; would have to create a fresh one"
6060
what ;
61-
let self = sr in
62-
let size = Db.SR.get_physical_size ~__context ~self in
63-
let utilisation = Db.SR.get_physical_utilisation ~__context ~self in
64-
let free_space = Int64.sub size utilisation in
61+
let free_space = Helpers.get_sr_free_space ~__context ~sr in
6562
if free_space < minimum_sr_size then (
6663
let sr = Ref.string_of sr in
67-
info "%s: SR %s size=%Ld utilisation=%Ld free=%Ld needed=%Ld"
68-
__FUNCTION__ sr size utilisation free_space minimum_sr_size ;
64+
info "%s: SR %s free=%Ld needed=%Ld" __FUNCTION__ sr free_space
65+
minimum_sr_size ;
6966
raise
7067
(Api_errors.Server_error
7168
(Api_errors.sr_source_space_insufficient, [sr])

0 commit comments

Comments
 (0)