[pve-devel] [RFC PATCH qemu-server 7/7] memory: 'current' value for dimms

Wolfgang Bumiller w.bumiller at proxmox.com
Tue Dec 20 12:49:26 CET 2016


This allows switching from the old hotplguging method to the
new one more easily by fetching the config of a running VM
by setting dimms to "current".
---
 PVE/QemuServer.pm        |  9 ++++--
 PVE/QemuServer/Memory.pm | 83 ++++++++++++++++++++++++++++++++++++++----------
 2 files changed, 74 insertions(+), 18 deletions(-)

diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index 66aad3a..6f7a9c7 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -235,10 +235,11 @@ my $confdesc = {
     dimms => {
 	optional => 1,
 	type => 'string',
-	pattern => '(?:\d+@\d+(?:x\d+)?(?:[ ;]\d+@\d+(?:x\d+)?)*)|none',
+	pattern => '(?:\d+@\d+(?:x\d+)?(?:[ ;]\d+@\d+(?:x\d+)?)*)|none|current',
 	description => 'When memory hotplug is available and dimms are explicitly specified,'
 	 .' the "memory" option becomes the static memory and the defined DIMMs are used for hotplugging.'
-	 .' This can be "none" to enable later dimm hotplugging with no initial ones added at startup.',
+	 .' This can be "none" to enable later dimm hotplugging with no initial ones added at startup.'
+	 .' The special value "current" can be used on a running machine to switch from the old hotplugging method to dimm hotplugging.',
     },
     balloon => {
         optional => 1,
@@ -4249,6 +4250,8 @@ sub vmconfig_apply_pending {
 
     # cold plug
 
+    my $defaults = load_defaults();
+
     my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
     while (my ($opt, $force) = each %$pending_delete_hash) {
 	die "internal error" if $opt =~ m/^unused/;
@@ -4279,6 +4282,8 @@ sub vmconfig_apply_pending {
 	    vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
 		if defined($conf->{$opt});
 	    $conf->{$opt} = $conf->{pending}->{$opt};
+	} elsif ($opt eq 'dimms') {
+	    $conf->{$opt} = PVE::QemuServer::Memory::qemu_dimm_hotplug($vmid, $conf, $defaults, $opt, $conf->{pending}->{$opt});
 	} else {
 	    $conf->{$opt} = $conf->{pending}->{$opt};
 	}
diff --git a/PVE/QemuServer/Memory.pm b/PVE/QemuServer/Memory.pm
index 89f1aff..4a2007d 100644
--- a/PVE/QemuServer/Memory.pm
+++ b/PVE/QemuServer/Memory.pm
@@ -254,13 +254,58 @@ my $qemu_update_dimm_config  = sub {
     return $value;
 };
 
+sub current_dimm_config {
+    my ($vmid, $conf, $defaults, $running, $cur_sizes_by_node) = @_;
+
+    my $old = $conf->{dimms};
+
+    if ($running) {
+	# use the above $cur_sizes_by_node info which was queried from qemu.
+	if (!$old) {
+	    use integer;
+	    # We used the old hotplug method before, so we first caclulcate the
+	    # amount of RAM the machine is currently using:
+	    my $memdevs = PVE::QemuServer::vm_mon_cmd_nocheck($vmid, "query-memdev");
+	    my $memory = 0;
+	    $memory += $_->{size} foreach @$memdevs;
+	    $memory /= 1024*1024;
+
+	    # Then subtract the dimm configuration
+	    foreach my $node (keys %$cur_sizes_by_node) {
+		my $sizes = $cur_sizes_by_node->{$node};
+		foreach my $size (keys %$sizes) {
+		    my $size_ids = $sizes->{$size};
+		    $memory -= $size * scalar(@$size_ids);
+		}
+	    }
+	    # Then we have our static memory:
+	    $conf->{memory} = $memory;
+	    PVE::QemuConfig->write_config($vmid, $conf);
+	}
+    } elsif ($old && $old ne 'current') {
+	# Not running and we have a dimm config, no change.
+	return $old;
+    } else {
+	# Not running and old config model was used. Convert:
+	$cur_sizes_by_node = {};
+	my $memory = $conf->{memory} || $defaults->{memory};
+	my $sockets = $conf->{sockets} || 1;
+	foreach_dimm($conf, $vmid, $memory, $sockets, sub {
+	    my ($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory) = @_;
+	    push @{$cur_sizes_by_node->{$numanode}->{$dimm_size}}, $name;
+	});
+    }
+
+    return &$qemu_update_dimm_config($vmid, $conf, $cur_sizes_by_node, 0)
+}
+
 sub qemu_dimm_hotplug {
     my ($vmid, $conf, $defaults, $opt, $value) = @_;
 
-    return $value if !PVE::QemuServer::check_running($vmid);
+    my $running = PVE::QemuServer::check_running($vmid);
 
-    if (!defined($value)) {
-	die "dimms need to be unplugged before deleting the dimms property\n"
+    if ($running && !defined($value)) {
+	die "dimms need to be unplugged before deleting the dimm property\n"
 	    if $conf->{dimms} && $conf->{dimms} ne 'none';
 	return undef;
     }
@@ -268,22 +313,28 @@ sub qemu_dimm_hotplug {
     my %allnodes;
     my %allids;
     my %allsizes;
-
-    my $qemudimms = qemu_dimm_list($vmid);
-
+    my $qemudimms;
     my $cur_sizes_by_node = {};
-    foreach my $id (keys %$qemudimms) {
-	my $dimm = $qemudimms->{$id};
-	my $node = $dimm->{node};
-	my $size = $dimm->{size};
-	my $megs = int($size/(1024*1024));
-	next if ($megs*1024*1024) != $size; # sanity check
-	$allids{$id} = 1;
-	$allnodes{$node} = 1;
-	$allsizes{$megs} = 1;
-	push @{$cur_sizes_by_node->{$node}->{$megs}}, $id;
+    if ($running) {
+	$qemudimms = qemu_dimm_list($vmid);
+	foreach my $id (keys %$qemudimms) {
+	    my $dimm = $qemudimms->{$id};
+	    my $node = $dimm->{node};
+	    my $size = $dimm->{size};
+	    my $megs = int($size/(1024*1024));
+	    next if ($megs*1024*1024) != $size; # sanity check
+	    $allids{$id} = 1;
+	    $allnodes{$node} = 1;
+	    $allsizes{$megs} = 1;
+	    push @{$cur_sizes_by_node->{$node}->{$megs}}, $id;
+	}
     }
 
+    return current_dimm_config($vmid, $conf, $defaults, $running, $cur_sizes_by_node)
+	if $value eq 'current';
+
+    return $value if !$running;
+
     my @new_dimms = parse_dimmlist($value);
     foreach my $dimm (@new_dimms) {
 	my ($dimm_size, $numanode) = @$dimm;
-- 
2.1.4





More information about the pve-devel mailing list