@@ -46,6 +46,9 @@ const (
4646
4747 // GenericCPUModel specifies the base CPU model for Features and Discovery CPU model types.
4848 GenericCPUModel = "qemu64"
49+
50+ MaxMemorySizeForHotplug = 256 * 1024 * 1024 * 1024 // 256 Gi (safely limit to not overlap somewhat conservative 38 bit physical address space)
51+ EnableMemoryHotplugThreshold = 1 * 1024 * 1024 * 1024 // 1 Gi (no hotplug for VMs with less than 1Gi)
4952)
5053
5154type KVVMOptions struct {
@@ -269,16 +272,65 @@ func (b *KVVM) SetCPU(cores int, coreFraction string) error {
269272 return nil
270273}
271274
275+ // SetMemory sets memory in kvvm.
276+ // There are 2 possibilities to set memory:
277+ // 1. Use domain.memory.guest field: it enabled memory hotplugging, but not set resources.limits.
278+ // 2. Explicitly set limits and requests in domain.resources. No hotplugging in this scenario.
279+ //
280+ // (1) is a new approach, and (2) should be respected for Running VMs started by previous version of the controller.
272281func (b * KVVM ) SetMemory (memorySize resource.Quantity ) {
282+ // TODO delete this in the future (around version 1.12).
283+ if b .ResourceExists && isVMRunningWithMemoryResources (b .Resource ) {
284+ // Keep resources as-is to not trigger a reboot.
285+ res := & b .Resource .Spec .Template .Spec .Domain .Resources
286+ if res .Requests == nil {
287+ res .Requests = make (map [corev1.ResourceName ]resource.Quantity )
288+ }
289+ if res .Limits == nil {
290+ res .Limits = make (map [corev1.ResourceName ]resource.Quantity )
291+ }
292+ res .Requests [corev1 .ResourceMemory ] = memorySize
293+ res .Limits [corev1 .ResourceMemory ] = memorySize
294+ return
295+ }
296+
297+ domain := & b .Resource .Spec .Template .Spec .Domain
298+ if domain .Memory == nil {
299+ domain .Memory = & virtv1.Memory {}
300+ }
301+ domain .Memory .Guest = & memorySize
302+
303+ // Enable memory hotplug if VM has enough memory (>= 1Gi).
304+ hotplugThreshold := resource .NewQuantity (EnableMemoryHotplugThreshold , resource .BinarySI )
305+ if memorySize .Cmp (* hotplugThreshold ) >= 0 {
306+ maxMemory := resource .NewQuantity (MaxMemorySizeForHotplug , resource .BinarySI )
307+ domain .Memory .MaxGuest = maxMemory
308+ }
309+
310+ // Remove memory limits and requests if set by previous versions.
273311 res := & b .Resource .Spec .Template .Spec .Domain .Resources
274- if res .Requests = = nil {
275- res .Requests = make ( map [ corev1.ResourceName ]resource. Quantity )
312+ if res .Requests ! = nil {
313+ delete ( res .Requests , corev1 .ResourceMemory )
276314 }
277315 if res .Limits == nil {
278- res .Limits = make (map [corev1.ResourceName ]resource.Quantity )
316+ delete (res .Limits , corev1 .ResourceMemory )
317+ }
318+ }
319+
320+ func isVMRunningWithMemoryResources (kvvm * virtv1.VirtualMachine ) bool {
321+ if kvvm == nil {
322+ return false
279323 }
280- res .Requests [corev1 .ResourceMemory ] = memorySize
281- res .Limits [corev1 .ResourceMemory ] = memorySize
324+
325+ if ! kvvm .Status .Created {
326+ return false
327+ }
328+
329+ res := kvvm .Spec .Template .Spec .Domain .Resources
330+ _ , hasMemoryRequests := res .Requests [corev1 .ResourceMemory ]
331+ _ , hasMemoryLimits := res .Limits [corev1 .ResourceMemory ]
332+
333+ return hasMemoryRequests && hasMemoryLimits
282334}
283335
284336func GetCPURequest (cores int , coreFraction string ) (* resource.Quantity , error ) {
0 commit comments