[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-API] [PATCH] prevent the artificial-reboot-delay being applied in the API callpath



# HG changeset patch
# User David Scott <dave.scott@xxxxxxxxxxxxx>
# Date 1268739025 0
# Node ID 012936d9d680683cd83cdcd2cd772985de142c50
# Parent  d455f3c74966447903add709174b57c8c50cc511
CA-38944: prevent the artificial-reboot-delay being accidentally applied to an 
API-driven reboot.

When the request queueing was fixed, a deliberate race was created between the 
background event thread and the API VM.reboot (etc). One of these threads wins 
the race and then the second thread becomes a no-op. Unfortunately the 
background event thread will apply the artificial-reboot-delay unless it is 
somehow prevented. We prevent it by storing the next reboot delay in xenstore 
(rather than the database) and setting it to 0 in the API call path.

Signed-off-by: David Scott <dave.scott@xxxxxxxxxxxxx>

diff -r d455f3c74966 -r 012936d9d680 ocaml/xapi/events.ml
--- a/ocaml/xapi/events.ml      Fri Mar 12 15:19:41 2010 +0000
+++ b/ocaml/xapi/events.ml      Tue Mar 16 11:30:25 2010 +0000
@@ -103,34 +103,16 @@
       with _ -> 0. (* ages ago *) in
     Unix.gettimeofday () -. start_time 
 
+  let artificial_reboot_key domid = Hotplug.get_private_path domid ^ "/" ^ 
Xapi_globs.artificial_reboot_delay
+
   (* When a VM is rebooted too quickly (from within) we insert a delay; on 
each _contiguous_
      quick reboot, this delay doubles *)
-  let insert_reboot_delay ~__context ~vm =
+  let calculate_reboot_delay ~__context ~vm domid =
     let delay_cap = 60 in (* 1 minute cap on reboot delays *)
-    let other_config = Db.VM.get_other_config ~__context ~self:vm in
-    let delay = 
-      try
-       let delay = int_of_string (List.assoc 
Xapi_globs.last_artificial_reboot_delay_key other_config) in
-       let next_delay = min (delay*2) delay_cap in  (* next delay doubles, 
capped at delay_cap *)
-       Db.VM.remove_from_other_config ~__context ~self:vm 
~key:Xapi_globs.last_artificial_reboot_delay_key;
-       Db.VM.add_to_other_config ~__context ~self:vm 
~key:Xapi_globs.last_artificial_reboot_delay_key ~value:(string_of_int 
next_delay);
-       delay
-      with _ ->  (* no delay on first quick reboot, 2s next time *)
-       (* in line below, we try to remove key from other-config anyway, just 
in-case this exn was generated because there _was_
-          a last reboot delay key in there, but it had invalid data contained 
it, causing the int_of_string to fail *)
-       (try Db.VM.remove_from_other_config ~__context ~self:vm 
~key:Xapi_globs.last_artificial_reboot_delay_key with _ -> ());
-       Db.VM.add_to_other_config ~__context ~self:vm 
~key:Xapi_globs.last_artificial_reboot_delay_key ~value:(string_of_int 2);
-       0 in
-       if Xapi_fist.disable_reboot_delay ()
-       then debug "FIST: disable_reboot_delay"
-    else begin
-         debug "Adding artificial delay on reboot for VM: %s. delay time=%d 
seconds" (Ref.string_of vm) delay;
-      Thread.delay (float_of_int delay)
-       end
+       let delay = try int_of_string (with_xs (fun xs -> xs.Xs.read 
(artificial_reboot_key domid))) with _ -> 0 in
+       let next_delay = min (delay * 2 + 2) delay_cap in
+       delay, next_delay
 
-  let clear_reboot_delay ~__context ~vm =
-    try Db.VM.remove_from_other_config ~__context ~self:vm 
~key:Xapi_globs.last_artificial_reboot_delay_key with _ -> ()
-      
   let perform_destroy ~__context ~vm token =
     TaskHelper.set_description ~__context "destroy";
     Xapi_vm.Shutdown.in_dom0_already_locked { Xapi_vm.TwoPhase.__context = 
__context; vm=vm; api_call_name="destroy"; clean=false };
@@ -142,13 +124,24 @@
 
   let perform_restart ~__context ~vm token =
     TaskHelper.set_description ~__context "restart";
-    if time_vm_ran_for ~__context ~vm < 
Xapi_globs.minimum_time_between_reboot_with_no_added_delay 
-    then insert_reboot_delay ~__context ~vm
-    else clear_reboot_delay ~__context ~vm;
-
+       let domid = Helpers.domid_of_vm ~__context ~self:vm in
+       let delay, next_delay = 
+         if Xapi_fist.disable_reboot_delay () then begin
+               debug "FIST: disable_reboot_delay";
+               0, 0
+         end else if time_vm_ran_for ~__context ~vm < 
Xapi_globs.minimum_time_between_reboot_with_no_added_delay then begin
+               calculate_reboot_delay ~__context ~vm domid
+         end else 0, 0 in
+       if delay <> 0 then begin
+         debug "Adding artificial delay on reboot for VM: %s. delay time=%d 
seconds" (Ref.string_of vm) delay;
+         Thread.delay (float_of_int delay);
+       end;
     try
-         Xapi_vm.Reboot.in_dom0_already_locked { Xapi_vm.TwoPhase.__context = 
__context; vm=vm; api_call_name="reboot"; clean=false };
-         update_allowed_ops_using_api ~__context vm
+               Xapi_vm.Reboot.in_dom0_already_locked { 
Xapi_vm.TwoPhase.__context = __context; vm=vm; api_call_name="reboot"; 
clean=false };
+               let domid' = Helpers.domid_of_vm ~__context ~self:vm in
+               assert (domid <> domid');
+               (with_xs (fun xs -> xs.Xs.write (artificial_reboot_key domid') 
(string_of_int next_delay)));
+               update_allowed_ops_using_api ~__context vm
     with e ->
       (* NB this can happen if the user has change the VM configuration to onw 
which
         cannot boot (eg not enough memory) and then rebooted inside the guest 
*)
diff -r d455f3c74966 -r 012936d9d680 ocaml/xapi/xapi_globs.ml
--- a/ocaml/xapi/xapi_globs.ml  Fri Mar 12 15:19:41 2010 +0000
+++ b/ocaml/xapi/xapi_globs.ml  Tue Mar 16 11:30:25 2010 +0000
@@ -375,8 +375,8 @@
 (* Default backlog supplied to Unix.listen *)
 let listen_backlog = 128
 
-(* Key on VM.other_config that records last artificial reboot delay *)
-let last_artificial_reboot_delay_key = "last_artificial_reboot_delay"
+(* Where the next artificial delay is stored in xenstore *)
+let artificial_reboot_delay = "artificial-reboot-delay"
 
 (* Xapi script hooks root *)
 let xapi_hooks_root = "/etc/xapi.d/"
diff -r d455f3c74966 -r 012936d9d680 ocaml/xapi/xapi_vm.ml
--- a/ocaml/xapi/xapi_vm.ml     Fri Mar 12 15:19:41 2010 +0000
+++ b/ocaml/xapi/xapi_vm.ml     Tue Mar 16 11:30:25 2010 +0000
@@ -366,6 +366,8 @@
                          error "VM: %s halted when asked to reboot" 
(Ref.string_of vm)
       end else begin
                debug "%s phase 0/3: no shutdown request required since this is 
a hard_reboot" api_call_name;
+               (* Make sure no-one inserts an artificial delay at this point *)
+               (with_xs (fun xs -> xs.Xs.write (Hotplug.get_private_path domid 
^ "/" ^ Xapi_globs.artificial_reboot_delay) "0"));
                (* The domain might be killed by the event thread. Again, this 
is ok. *)
                Helpers.log_exn_continue (Printf.sprintf "Xc.domain_shutdown 
domid=%d Xc.Reboot" domid)
                        (fun () -> 
3 files changed, 27 insertions(+), 32 deletions(-)
ocaml/xapi/events.ml     |   53 +++++++++++++++++++---------------------------
ocaml/xapi/xapi_globs.ml |    4 +--
ocaml/xapi/xapi_vm.ml    |    2 +


Attachment: xen-api.hg.patch
Description: Text Data

_______________________________________________
xen-api mailing list
xen-api@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/mailman/listinfo/xen-api

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.