# HG changeset patch # User David Scott # Date 1264521078 0 # Node ID b001a306fbc2128979e1b7471bc34d14e6a03a02 # Parent 22cd3f304b9e0818b80ac5a40e6d4c6438c5e58a CA-36316: fix a bug where the domain's maxmem gets out of sync in the case when no ballooning is required e.g. if dynamic_min = dynamic_max. This causes subsequent suspend/resume or migrate operations to demand more memory than they strictly need. The problem is caused by: 1. xapi creates the domain and sets maxmem = static_max 2. squeezed modifies maxmem only if it is doing some squeezing; if dynamic_min = dynamic_max then no squeezing is necessary 3. xapi uses max(memory_actual, maxmem) as the amount "needed" by suspend/resume/migrate Since squeezed is managing maxmem, this patch makes it always reset maxmems to low values in its polling loop. Note that there is a cache so we don't issue more hypercalls than we actually need. Also fix a logging glitch where if dynamic_min = dynamic_max, large negative numbers were written to the log (but not used for anything) Signed-off-by: David Scott diff -r 22cd3f304b9e -r b001a306fbc2 ocaml/xenops/squeeze.ml --- a/ocaml/xenops/squeeze.ml Thu Jan 21 15:45:09 2010 +0000 +++ b/ocaml/xenops/squeeze.ml Tue Jan 26 15:51:18 2010 +0000 @@ -292,11 +292,13 @@ (* We allocate surplus memory in proportion to each domain's dynamic_range: *) let allocate gamma domain = Int64.of_float (gamma *. (Int64.to_float (range domain))) in (* gamma = the proportion where 0 <= gamma <= 1 *) - let total_range = Int64.to_float (sum (List.map range domains)) in - let gamma' = Int64.to_float surplus_memory_kib /. total_range in + let total_range = sum (List.map range domains) in + let gamma' = Int64.to_float surplus_memory_kib /. (Int64.to_float total_range) in let gamma = constrain 0. 1. gamma' in + debug "total_range = %Ld gamma = %f gamma' = %f" total_range gamma gamma'; if verbose - then debug "Total additional memory over dynamic_min = %Ld KiB; will set gamma = %.2f (leaving unallocated %Ld KiB)" surplus_memory_kib gamma (Int64.of_float (total_range *. (gamma' -. gamma))); + then debug "Total additional memory over dynamic_min = %Ld KiB; will set gamma = %.2f (leaving unallocated %Ld KiB)" surplus_memory_kib gamma + (if total_range = 0L then 0L else Int64.of_float (Int64.to_float total_range *. (gamma' -. gamma))); List.map (fun domain -> domain, domain.dynamic_min_kib +* (allocate gamma domain)) domains @@ -521,30 +523,18 @@ let debug_string = String.concat "; " (host_debug_string :: (List.map (fun domain -> short_string_of_domain domain ^ (new_target_direction domain)) host.domains)) in debug "%s" debug_string; - (* Deal with inactive and 'never been run' domains *) - List.iter (fun domid -> - try - let domain = IntMap.find domid host.domid_to_domain in - let mem_max_kib = min domain.target_kib domain.memory_actual_kib in - debug "Setting inactive domain %d mem_max = %Ld" domid mem_max_kib; - io.domain_setmaxmem domid mem_max_kib - with Not_found -> - debug "WARNING: inactive domain %d not in map" domid - ) declared_inactive_domids; - (* Next deal with the active domains (which may have new targets) *) - List.iter (fun domid -> - try - let domain = IntMap.find domid host.domid_to_domain in - let mem_max_kib = - if List.mem_assoc domid new_targets - then List.assoc domid new_targets - else domain.target_kib in - debug "Setting active domain %d mem_max = %Ld" domid mem_max_kib; - io.domain_setmaxmem domid mem_max_kib - with Not_found -> - debug "WARNING: active domain %d not in map" domid - ) declared_active_domids; - + (* For each domid, decide what maxmem should be *) + let maxmems = IntMap.mapi + (fun domid domain -> + if List.mem domid declared_inactive_domids + then min domain.target_kib domain.memory_actual_kib + else + if List.mem_assoc domid new_targets + then List.assoc domid new_targets + else domain.target_kib) host.domid_to_domain in + + IntMap.iter io.domain_setmaxmem maxmems; + begin match result with | Success -> if io.verbose diff -r 22cd3f304b9e -r b001a306fbc2 ocaml/xenops/squeeze_xen.ml --- a/ocaml/xenops/squeeze_xen.ml Thu Jan 21 15:45:09 2010 +0000 +++ b/ocaml/xenops/squeeze_xen.ml Tue Jan 26 15:51:18 2010 +0000 @@ -359,11 +359,20 @@ reserved_kib := Int64.add !reserved_kib non_domain_reservations; let host = Squeeze.make_host ~domains ~free_mem_kib:(Int64.sub free_mem_kib !reserved_kib) in + Domain.gc (List.map (fun di -> di.Xc.domid) domain_infolist); + (* Externally-visible side-effects. It's a bit ugly to include these here: *) update_cooperative_table host; update_cooperative_flags cnx; - Domain.gc (List.map (fun di -> di.Xc.domid) domain_infolist); + (* It's always safe to _decrease_ a domain's maxmem towards target. This catches the case + where a toolstack creates a domain with maxmem = static_max and target < static_max (eg + CA-36316) *) + let updates = Squeeze.IntMap.fold (fun domid domain updates -> + if domain.Squeeze.target_kib < (Domain.get_maxmem (xc, xs) domid) + then Squeeze.IntMap.add domid domain.Squeeze.target_kib updates + else updates) host.Squeeze.domid_to_domain Squeeze.IntMap.empty in + Squeeze.IntMap.iter (Domain.set_maxmem_noexn (xc, xs)) updates; Printf.sprintf "F%Ld S%Ld R%Ld T%Ld" free_pages_kib scrub_pages_kib !reserved_kib total_pages_kib, host