[pve-devel] [PATCH] memory hotplug patch v4
Alexandre Derumier
aderumier at odiso.com
Wed Aug 27 06:13:46 CEST 2014
From: Stefan Priebe <s.priebe at profihost.ag>
This patch allow to hotplug|define pc dimm devices memory
Minimum size is 128M
Maximum devices is 255
(tested under debian and windows).
vmid.conf
---------
dimm0: size=128
dimm1: size=512
dimm255: size=1024
memory: 1024
maxmemory: 8192
total running memory is : memory + dimmX.
dimmX devices are not seen by os at start, so need to have "memory" enough big to load kernel
hotplug
----
qm set <vmid> -dimm0 128
unplug (not yet implemented in qemu)
------
qm set <vmid> -delete dimm0
linux guest
-----------
-acpi hotplug module should be loaded in guest
-need a recent kernel. (tested with 3.10)
can be enable automaticly, adding:
/lib/udev/rules.d/80-hotplug-cpu-mem.rules
SUBSYSTEM=="cpu", ACTION=="add", TEST=="online", ATTR{online}=="0", \
ATTR{online}="1"
SUBSYSTEM=="memory", ACTION=="add", TEST=="state", ATTR{state}=="offline", \
ATTR{state}="online"
windows guest
-------------
works out of the box:
- windows 2012 standard
- windows 2008 enterprise/datacenter
Signed-off-by: Stefan Priebe <s.priebe at profihost.ag>
Signed-off-by: Alexandre Derumier <aderumier at odiso.com>
---
PVE/API2/Qemu.pm | 8 ++++
PVE/QemuServer.pm | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 112 insertions(+), 1 deletion(-)
diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index 985a9f8..084e4d7 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -727,6 +727,10 @@ my $vmconfig_delete_option = sub {
} else {
die "error hot-unplug $opt $unplugwarning" if !PVE::QemuServer::vm_deviceunplug($vmid, $conf, $opt);
}
+ if ($opt =~ m/^dimm(\d+)$/) { #dimms
+
+ PVE::QemuServer::qemu_memory_unplug($vmid, $conf, $opt);
+ }
if ($isDisk) {
my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
@@ -997,6 +1001,10 @@ my $update_vm_api = sub {
&$vmconfig_update_net($rpcenv, $authuser, $conf, $storecfg, $vmid,
$opt, $param->{$opt});
+ } elsif ($opt =~ m/^dimm(\d+)$/) { #dimms
+
+ PVE::QemuServer::qemu_memory_hotplug($vmid, $conf, $opt, $param->{$opt});
+
} else {
if($opt eq 'tablet' && $param->{$opt} == 1){
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 49356f2..1dbf76e 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -307,6 +307,12 @@ EODESC
minimum => 1,
default => 1,
},
+ maxmemory => {
+ optional => 1,
+ type => 'integer',
+ description => "Maximum memory for hotplug.",
+ minimum => 1,
+ },
acpi => {
optional => 1,
type => 'boolean',
@@ -477,6 +483,7 @@ my $MAX_UNUSED_DISKS = 8;
my $MAX_HOSTPCI_DEVICES = 4;
my $MAX_SERIAL_PORTS = 4;
my $MAX_PARALLEL_PORTS = 3;
+my $MAX_DIMMS = 255;
my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3'];
@@ -514,6 +521,20 @@ for (my $i = 0; $i < $MAX_NETS; $i++) {
$confdesc->{"net$i"} = $netdesc;
}
+my $dimmdesc = {
+ optional => 1,
+ type => 'string',
+ typetext => "size=<BYTES>,
+ description => <<EODESCR,
+Later / Hotplugged memory DIMM modules
+EODESCR
+};
+PVE::JSONSchema::register_standard_option("pve-qm-dimm", $dimmdesc);
+
+for (my $i = 0; $i < $MAX_DIMMS; $i++) {
+ $confdesc->{"dimm$i"} = $dimmdesc;
+}
+
my $drivename_hash;
my $idedesc = {
@@ -2780,7 +2801,27 @@ sub config_to_command {
push @$devices, '-device', print_drivedevice_full($storecfg, $conf, $vmid, $drive, $bridges);
});
- push @$cmd, '-m', $conf->{memory} || $defaults->{memory};
+ my $memory = $conf->{memory} || $defaults->{memory};
+ my $totalmemory = $memory;
+ for (my $i = 0; $i < $MAX_DIMMS; $i++) {
+ next if !exists $conf->{"dimm$i"};
+ $conf->{"dimm$i"} =~ m/size=(\d+)/ or next;
+ my $dimmsize = $1;
+ die "dimm size should be a multiple of 128!\n" if ($dimmsize % 128 != 0);
+
+ push @$cmd, "-object" , "memory-backend-ram,id=mem$i,size=".int(${dimmsize}*1024*1024);
+ push @$cmd, "-device", "pc-dimm,id=dimm$i,memdev=mem$i";
+ $totalmemory += $dimmsize;
+ }
+
+ if ($conf->{maxmemory}) {
+ die "Total memory is bigger than maxmemory\n" if $totalmemory > $conf->{maxmemory};
+ push @$cmd, '-m', "size=".$memory.",slots=$MAX_DIMMS,maxmem=".$conf->{maxmemory}."M";
+ push @$cmd, "-numa", "node" if ($conf->{ostype} && $conf->{ostype} =~ m/^w/);
+
+ } else {
+ push @$cmd, '-m', $memory;
+ }
for (my $i = 0; $i < $MAX_NETS; $i++) {
next if !$conf->{"net$i"};
@@ -3138,6 +3179,68 @@ sub qemu_cpu_hotplug {
}
}
+sub qemu_memory_hotplug {
+ my ($vmid, $conf, $dimm, $size) = @_;
+
+ return if !check_running($vmid);
+
+ die "maxmemory is not defined" if !$conf->{maxmemory};
+
+ die "dimm already exist" if $conf->{$dimm};
+
+ die "dimm size should be a multiple of 128!\n" if ($size % 128 != 0);
+
+ my $defaults = load_defaults();
+ my $memory = $conf->{memory} || $defaults->{memory};
+ my $totalmemory = $memory;
+ for (my $i = 0; $i < $MAX_DIMMS; $i++) {
+ next if !exists $conf->{"dimm$i"};
+ $conf->{"dimm$i"} =~ m/size=(\d+)/ or next;
+ my $dimmsize = $1;
+ $totalmemory += $dimmsize;
+ }
+ $totalmemory += $size;
+
+ die "you cannot add more memory than maxmemory!\n" if $totalmemory > $conf->{'maxmemory'};
+
+ eval {
+ # size is in BYTES
+ vm_mon_cmd($vmid, "object-add", 'qom-type' => "memory-backend-ram", id => "mem$dimm", props => { size => int($size*1024*1024) } )
+ };
+ my $err = $@;
+
+ $conf->{"$dimm"} = "size=$size";
+
+ # slot is consumed even on failure and also if device_add fails
+ update_config_nolock($vmid, $conf, 1);
+
+ if (!$err) {
+ eval {
+ vm_mon_cmd($vmid, "device_add", driver => "pc-dimm", id => "$dimm", memdev => "mem$dimm");
+
+ };
+ $err = $@;
+ }
+
+ die "Memory hot add failed!: $err\n" if $err;
+}
+
+sub qemu_memory_unplug {
+ my ($vmid, $conf, $dimm) = @_;
+
+ return if !check_running($vmid);
+
+ die "memory unplug is not yet implemented";
+
+ eval {
+ vm_mon_cmd($vmid, "device_del", id => $dimm);
+ };
+ if($@){
+ die "error unplug dimm device $dimm";
+ }
+
+}
+
sub qemu_block_set_io_throttle {
my ($vmid, $deviceid, $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr) = @_;
--
1.7.10.4
More information about the pve-devel
mailing list