memory: update: Update state using the memory removed.

If the memory is reduced , its cgroup in the VM was updated properly. But the
runtime assumed that the memory was also removed from the VM.

Then when it is added more memory again, more is added (but not needed).

Fixes: #801

Signed-off-by: Jose Carlos Venegas Munoz <jose.carlos.venegas.munoz@intel.com>
This commit is contained in:
Jose Carlos Venegas Munoz 2018-09-29 11:15:58 -05:00
parent 532e0bbf75
commit 4697cf3c79
2 changed files with 44 additions and 17 deletions

View File

@ -1301,9 +1301,13 @@ func (c *Container) memHotplugValid(mem uint32) (uint32, error) {
return uint32(math.Ceil(float64(mem)/float64(memorySectionSizeMB))) * memorySectionSizeMB, nil return uint32(math.Ceil(float64(mem)/float64(memorySectionSizeMB))) * memorySectionSizeMB, nil
} }
func (c *Container) updateMemoryResources(oldResources, newResources ContainerResources) error { func (c *Container) updateMemoryResources(oldResources ContainerResources, newResources *ContainerResources) error {
oldMemMB := oldResources.MemMB oldMemMB := oldResources.MemMB
newMemMB := newResources.MemMB newMemMB := newResources.MemMB
c.Logger().WithFields(logrus.Fields{
"old-mem": fmt.Sprintf("%dMB", oldMemMB),
"new-mem": fmt.Sprintf("%dMB", newMemMB),
}).Debug("Request update memory")
if oldMemMB == newMemMB { if oldMemMB == newMemMB {
c.Logger().WithFields(logrus.Fields{ c.Logger().WithFields(logrus.Fields{
@ -1325,16 +1329,37 @@ func (c *Container) updateMemoryResources(oldResources, newResources ContainerRe
addMemDevice := &memoryDevice{ addMemDevice := &memoryDevice{
sizeMB: int(memHotplugMB), sizeMB: int(memHotplugMB),
} }
_, err = c.sandbox.hypervisor.hotplugAddDevice(addMemDevice, memoryDev) data, err := c.sandbox.hypervisor.hotplugAddDevice(addMemDevice, memoryDev)
if err != nil { if err != nil {
return err return err
} }
newResources.MemMB = newMemMB memoryAdded, ok := data.(int)
if !ok {
return fmt.Errorf("Could not get the memory added, got %+v", data)
}
newResources.MemMB = oldMemMB + uint32(memoryAdded)
if err := c.sandbox.agent.onlineCPUMem(0, false); err != nil { if err := c.sandbox.agent.onlineCPUMem(0, false); err != nil {
return err return err
} }
} }
// hot remove memory unsupported if oldMemMB > newMemMB {
// Try to remove a memory device with the difference
// from new memory and old memory
removeMem := &memoryDevice{
sizeMB: int(oldMemMB - newMemMB),
}
data, err := c.sandbox.hypervisor.hotplugRemoveDevice(removeMem, memoryDev)
if err != nil {
return err
}
memoryRemoved, ok := data.(int)
if !ok {
return fmt.Errorf("Could not get the memory added, got %+v", data)
}
newResources.MemMB = oldMemMB - uint32(memoryRemoved)
newResources.MemMB = oldResources.MemMB
}
return nil return nil
} }
@ -1358,7 +1383,7 @@ func (c *Container) updateResources(oldResources, newResources ContainerResource
// Memory is not updated if memory limit not set // Memory is not updated if memory limit not set
if newResources.MemMB != 0 { if newResources.MemMB != 0 {
if err := c.updateMemoryResources(oldResources, newResources); err != nil { if err := c.updateMemoryResources(oldResources, &newResources); err != nil {
return err return err
} }

View File

@ -7,7 +7,6 @@ package virtcontainers
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
@ -913,7 +912,7 @@ func (q *qemu) hotplugDevice(devInfo interface{}, devType deviceType, op operati
return nil, q.hotplugVFIODevice(device, op) return nil, q.hotplugVFIODevice(device, op)
case memoryDev: case memoryDev:
memdev := devInfo.(*memoryDevice) memdev := devInfo.(*memoryDevice)
return nil, q.hotplugMemory(memdev, op) return q.hotplugMemory(memdev, op)
case netDev: case netDev:
device := devInfo.(*VirtualEndpoint) device := devInfo.(*VirtualEndpoint)
return nil, q.hotplugNetDevice(device, op) return nil, q.hotplugNetDevice(device, op)
@ -1047,24 +1046,27 @@ func (q *qemu) hotplugRemoveCPUs(amount uint32) (uint32, error) {
return amount, q.storage.storeHypervisorState(q.id, q.state) return amount, q.storage.storeHypervisorState(q.id, q.state)
} }
func (q *qemu) hotplugMemory(memDev *memoryDevice, op operation) error { func (q *qemu) hotplugMemory(memDev *memoryDevice, op operation) (int, error) {
if memDev.sizeMB < 0 { if memDev.sizeMB < 0 {
return fmt.Errorf("cannot hotplug negative size (%d) memory", memDev.sizeMB) return 0, fmt.Errorf("cannot hotplug negative size (%d) memory", memDev.sizeMB)
} }
// We do not support memory hot unplug. // We do not support memory hot unplug.
if op == removeDevice { if op == removeDevice {
return errors.New("cannot hot unplug memory device") // Dont fail for now, until we fix it.
// We return that we only unplugged 0
q.Logger().Warn("hot-remove VM memory not supported")
return 0, nil
} }
err := q.qmpSetup() err := q.qmpSetup()
if err != nil { if err != nil {
return err return 0, err
} }
maxMem, err := q.hostMemMB() maxMem, err := q.hostMemMB()
if err != nil { if err != nil {
return err return 0, err
} }
// calculate current memory // calculate current memory
@ -1072,13 +1074,13 @@ func (q *qemu) hotplugMemory(memDev *memoryDevice, op operation) error {
// Don't exceed the maximum amount of memory // Don't exceed the maximum amount of memory
if currentMemory+memDev.sizeMB > int(maxMem) { if currentMemory+memDev.sizeMB > int(maxMem) {
return fmt.Errorf("Unable to hotplug %d MiB memory, the SB has %d MiB and the maximum amount is %d MiB", return 0, fmt.Errorf("Unable to hotplug %d MiB memory, the SB has %d MiB and the maximum amount is %d MiB",
memDev.sizeMB, currentMemory, q.config.MemorySize) memDev.sizeMB, currentMemory, q.config.MemorySize)
} }
memoryDevices, err := q.qmpMonitorCh.qmp.ExecQueryMemoryDevices(q.qmpMonitorCh.ctx) memoryDevices, err := q.qmpMonitorCh.qmp.ExecQueryMemoryDevices(q.qmpMonitorCh.ctx)
if err != nil { if err != nil {
return fmt.Errorf("failed to query memory devices: %v", err) return 0, fmt.Errorf("failed to query memory devices: %v", err)
} }
if len(memoryDevices) != 0 { if len(memoryDevices) != 0 {
@ -1088,15 +1090,15 @@ func (q *qemu) hotplugMemory(memDev *memoryDevice, op operation) error {
return q.hotplugAddMemory(memDev) return q.hotplugAddMemory(memDev)
} }
func (q *qemu) hotplugAddMemory(memDev *memoryDevice) error { func (q *qemu) hotplugAddMemory(memDev *memoryDevice) (int, error) {
err := q.qmpMonitorCh.qmp.ExecHotplugMemory(q.qmpMonitorCh.ctx, "memory-backend-ram", "mem"+strconv.Itoa(memDev.slot), "", memDev.sizeMB) err := q.qmpMonitorCh.qmp.ExecHotplugMemory(q.qmpMonitorCh.ctx, "memory-backend-ram", "mem"+strconv.Itoa(memDev.slot), "", memDev.sizeMB)
if err != nil { if err != nil {
q.Logger().WithError(err).Error("hotplug memory") q.Logger().WithError(err).Error("hotplug memory")
return err return 0, err
} }
q.state.HotpluggedMemory += memDev.sizeMB q.state.HotpluggedMemory += memDev.sizeMB
return q.storage.storeHypervisorState(q.id, q.state) return memDev.sizeMB, q.storage.storeHypervisorState(q.id, q.state)
} }
func (q *qemu) pauseSandbox() error { func (q *qemu) pauseSandbox() error {