[lxc-devel] [lxd/master] VM: Adds support for live memory growth back to boot time memory size
tomponline on Github
lxc-bot at linuxcontainers.org
Thu Oct 1 11:30:36 UTC 2020
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 391 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20201001/a78f8a4b/attachment-0001.bin>
-------------- next part --------------
From 124aad5233ee89720edd6c137500d8c81a300508 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 1 Oct 2020 12:25:37 +0100
Subject: [PATCH 1/5] lxd/instance/drivers/qmp/monitor: Renames
GetMemoryBalloonSizeBytes
And makes comments more accurate.
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/instance/drivers/qmp/monitor.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lxd/instance/drivers/qmp/monitor.go b/lxd/instance/drivers/qmp/monitor.go
index 11c011da38..9d5eb789ff 100644
--- a/lxd/instance/drivers/qmp/monitor.go
+++ b/lxd/instance/drivers/qmp/monitor.go
@@ -323,8 +323,8 @@ func (m *Monitor) GetCPUs() ([]int, error) {
return pids, nil
}
-// GetBalloonSizeBytes returns the current size of the memory balloon in bytes.
-func (m *Monitor) GetBalloonSizeBytes() (int64, error) {
+// GetMemoryBalloonSizeBytes returns effective size of the memory in bytes (considering the current balloon size).
+func (m *Monitor) GetMemoryBalloonSizeBytes() (int64, error) {
respRaw, err := m.qmp.Run([]byte("{'execute': 'query-balloon'}"))
if err != nil {
m.Disconnect()
From 6f9663cc9d33bd27376c28155830eca3707b3072 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 1 Oct 2020 12:26:00 +0100
Subject: [PATCH 2/5] lxd/instance/drivers/qmp/monitor: Renames
SetMemoryBalloonSizeBytes
And makes comments more accurate.
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/instance/drivers/qmp/monitor.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lxd/instance/drivers/qmp/monitor.go b/lxd/instance/drivers/qmp/monitor.go
index 9d5eb789ff..da917d78af 100644
--- a/lxd/instance/drivers/qmp/monitor.go
+++ b/lxd/instance/drivers/qmp/monitor.go
@@ -346,8 +346,8 @@ func (m *Monitor) GetMemoryBalloonSizeBytes() (int64, error) {
return respDecoded.Return.Actual, nil
}
-// SetBalloonSizeBytes sets the size of the memory balloon in bytes.
-func (m *Monitor) SetBalloonSizeBytes(sizeBytes int64) error {
+// SetMemoryBalloonSizeBytes sets the size of the memory in bytes (which will resize the balloon as needed).
+func (m *Monitor) SetMemoryBalloonSizeBytes(sizeBytes int64) error {
respRaw, err := m.qmp.Run([]byte(fmt.Sprintf("{'execute': 'balloon', 'arguments': {'value': %d}}", sizeBytes)))
if err != nil {
m.Disconnect()
From 6ced837edcae82aee518f31af32c13fd06d36d88 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 1 Oct 2020 12:26:24 +0100
Subject: [PATCH 3/5] lxd/instance/drivers/qmp/monitor: Adds GetMemorySizeBytes
function
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/instance/drivers/qmp/monitor.go | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
diff --git a/lxd/instance/drivers/qmp/monitor.go b/lxd/instance/drivers/qmp/monitor.go
index da917d78af..e02bc96590 100644
--- a/lxd/instance/drivers/qmp/monitor.go
+++ b/lxd/instance/drivers/qmp/monitor.go
@@ -323,6 +323,29 @@ func (m *Monitor) GetCPUs() ([]int, error) {
return pids, nil
}
+// GetMemorySizeBytes returns the current size of the base memory in bytes.
+func (m *Monitor) GetMemorySizeBytes() (int64, error) {
+ respRaw, err := m.qmp.Run([]byte("{'execute': 'query-memory-size-summary'}"))
+ if err != nil {
+ m.Disconnect()
+ return -1, ErrMonitorDisconnect
+ }
+
+ // Process the response.
+ var respDecoded struct {
+ Return struct {
+ BaseMemory int64 `json:"base-memory"`
+ } `json:"return"`
+ }
+
+ err = json.Unmarshal(respRaw, &respDecoded)
+ if err != nil {
+ return -1, ErrMonitorBadReturn
+ }
+
+ return respDecoded.Return.BaseMemory, nil
+}
+
// GetMemoryBalloonSizeBytes returns effective size of the memory in bytes (considering the current balloon size).
func (m *Monitor) GetMemoryBalloonSizeBytes() (int64, error) {
respRaw, err := m.qmp.Run([]byte("{'execute': 'query-balloon'}"))
From 6c6cd366eeb1f5e0c3a6106f15975f8de6408f14 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 1 Oct 2020 12:26:49 +0100
Subject: [PATCH 4/5] lxd/instance/drivers/driver/qemu: Adds qemuDefaultMemSize
constant
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/instance/drivers/driver_qemu.go | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/lxd/instance/drivers/driver_qemu.go b/lxd/instance/drivers/driver_qemu.go
index 3fed78efcb..af18d1dfe7 100644
--- a/lxd/instance/drivers/driver_qemu.go
+++ b/lxd/instance/drivers/driver_qemu.go
@@ -69,6 +69,9 @@ const qemuUnsafeIO = "unsafeio"
// qemuSerialChardevName is used to communicate state via qmp between Qemu and LXD.
const qemuSerialChardevName = "qemu_serial-chardev"
+// qemuDefaultMemSize is the default memory size for VMs if not limit specified.
+const qemuDefaultMemSize = "1GiB"
+
var errQemuAgentOffline = fmt.Errorf("LXD VM agent isn't currently running")
var vmConsole = map[int]bool{}
@@ -1924,7 +1927,7 @@ func (vm *qemu) addCPUMemoryConfig(sb *strings.Builder) error {
// Configure memory limit.
memSize := vm.expandedConfig["limits.memory"]
if memSize == "" {
- memSize = "1GiB" // Default to 1GiB if no memory limit specified.
+ memSize = qemuDefaultMemSize // Default if no memory limit specified.
}
memSizeBytes, err := units.ParseByteSizeString(memSize)
From c71a3f8ec288b9c29eb8908db316614c1d0998ef Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parrott at canonical.com>
Date: Thu, 1 Oct 2020 12:27:24 +0100
Subject: [PATCH 5/5] lxd/instance/drivers/driver/qemu: Updates
updateMemoryLimit to allow memory resize back to boot time size
- Fixes bug where unsetting limits.memory didn't try and resize memory back to default size.
- Allows live memory growth back to original boot time size.
- Makes comments more accurate base on qemu's actual balloon size commands.
Signed-off-by: Thomas Parrott <thomas.parrott at canonical.com>
---
lxd/instance/drivers/driver_qemu.go | 26 +++++++++++++++++---------
1 file changed, 17 insertions(+), 9 deletions(-)
diff --git a/lxd/instance/drivers/driver_qemu.go b/lxd/instance/drivers/driver_qemu.go
index af18d1dfe7..547e5fb088 100644
--- a/lxd/instance/drivers/driver_qemu.go
+++ b/lxd/instance/drivers/driver_qemu.go
@@ -2975,9 +2975,12 @@ func (vm *qemu) Update(args db.InstanceArgs, userRequested bool) error {
return nil
}
-// updateMemoryLimit live updates the VM's memory limit by shrinking the balloon device.
-// Only memory shrinking is supported at this time.
+// updateMemoryLimit live updates the VM's memory limit by reszing the balloon device.
func (vm *qemu) updateMemoryLimit(newLimit string) error {
+ if newLimit == "" {
+ newLimit = qemuDefaultMemSize
+ }
+
if shared.IsTrue(vm.expandedConfig["limits.memory.hugepages"]) {
return fmt.Errorf("Cannot live update memory limit when using huge pages")
}
@@ -2994,27 +2997,32 @@ func (vm *qemu) updateMemoryLimit(newLimit string) error {
return err // The VM isn't running as no monitor socket available.
}
- curSizeBytes, err := monitor.GetBalloonSizeBytes()
+ baseSizeBytes, err := monitor.GetMemorySizeBytes()
+ if err != nil {
+ return err
+ }
+
+ curSizeBytes, err := monitor.GetMemoryBalloonSizeBytes()
if err != nil {
return err
}
if curSizeBytes == newSizeBytes {
return nil
- } else if curSizeBytes < newSizeBytes {
- return fmt.Errorf("Cannot increase memory size when VM is running")
+ } else if baseSizeBytes < newSizeBytes {
+ return fmt.Errorf("Cannot increase memory size beyond boot time size when VM is running")
}
- // Shrink balloon device.
- err = monitor.SetBalloonSizeBytes(newSizeBytes)
+ // Set effective memory size.
+ err = monitor.SetMemoryBalloonSizeBytes(newSizeBytes)
if err != nil {
return err
}
- // Shrinking the balloon can take time, so poll the actual balloon size to check it has shrunk within 1%
+ // Changing the memory balloon can take time, so poll the effectice size to check it has shrunk within 1%
// of the target size, which we then take as success (it may still continue to shrink closer to target).
for i := 0; i < 5; i++ {
- curSizeBytes, err = monitor.GetBalloonSizeBytes()
+ curSizeBytes, err = monitor.GetMemoryBalloonSizeBytes()
if err != nil {
return err
}
More information about the lxc-devel
mailing list