]> git.proxmox.com Git - qemu-server.git/commitdiff
add memory parser
authorAlexandre Derumier <aderumier@odiso.com>
Mon, 4 Sep 2023 11:39:49 +0000 (13:39 +0200)
committerThomas Lamprecht <t.lamprecht@proxmox.com>
Mon, 18 Sep 2023 15:08:48 +0000 (17:08 +0200)
In preparation to add more properties to the memory configuration like
maximum hotpluggable memory and whether virtio-mem devices should be
used.

This also allows to get rid of the cyclic include of PVE::QemuServer
in the memory module.

Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
[FE: also convert new usage in get_derived_property
     remove cyclic include of PVE::QemuServer
     add commit message]
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
PVE/API2/Qemu.pm
PVE/QemuConfig.pm
PVE/QemuMigrate.pm
PVE/QemuServer.pm
PVE/QemuServer/Helpers.pm
PVE/QemuServer/Memory.pm

index 9606e72e59dadf2bcfd1653a05d1c1c141e160d5..774b0c712b1ea9381536a58b76d7bb65c1eb7048 100644 (file)
@@ -32,6 +32,7 @@ use PVE::QemuServer::Drive;
 use PVE::QemuServer::ImportDisk;
 use PVE::QemuServer::Monitor qw(mon_cmd);
 use PVE::QemuServer::Machine;
+use PVE::QemuServer::Memory qw(get_current_memory);
 use PVE::QemuServer::PCI;
 use PVE::QemuServer::USB;
 use PVE::QemuMigrate;
@@ -1573,8 +1574,6 @@ my $update_vm_api  = sub {
 
     my $storecfg = PVE::Storage::config();
 
-    my $defaults = PVE::QemuServer::load_defaults();
-
     &$resolve_cdrom_alias($param);
 
     # now try to verify all parameters
@@ -1694,7 +1693,9 @@ my $update_vm_api  = sub {
        }
 
        if ($param->{memory} || defined($param->{balloon})) {
-           my $maxmem = $param->{memory} || $conf->{pending}->{memory} || $conf->{memory} || $defaults->{memory};
+
+           my $memory = $param->{memory} || $conf->{pending}->{memory} || $conf->{memory};
+           my $maxmem = get_current_memory($memory);
            my $balloon = defined($param->{balloon}) ? $param->{balloon} : $conf->{pending}->{balloon} || $conf->{balloon};
 
            die "balloon value too large (must be smaller than assigned memory)\n"
index 10e692998e9cdb089273f77a0ce69b262e179c5c..d49d88230a8e2329d5a62374c508d153310b0a3f 100644 (file)
@@ -12,6 +12,7 @@ use PVE::QemuServer::Helpers;
 use PVE::QemuServer::Monitor qw(mon_cmd);
 use PVE::QemuServer;
 use PVE::QemuServer::Machine;
+use PVE::QemuServer::Memory qw(get_current_memory);
 use PVE::Storage;
 use PVE::Tools;
 use PVE::Format qw(render_bytes render_duration);
@@ -208,8 +209,7 @@ sub __snapshot_save_vmstate {
        $target = PVE::QemuServer::find_vmstate_storage($conf, $storecfg);
     }
 
-    my $defaults = PVE::QemuServer::load_defaults();
-    my $mem_size = $conf->{memory} // $defaults->{memory};
+    my $mem_size = get_current_memory($conf->{memory});
     my $driver_state_size = 500; # assume 500MB is enough to safe all driver state;
     # our savevm-start does live-save of the memory until the space left in the
     # volume is just enough for the remaining memory content + internal state
@@ -549,8 +549,8 @@ sub get_derived_property {
        my $cpus =
            ($conf->{sockets} || $defaults->{sockets}) * ($conf->{cores} || $defaults->{cores});
        return $conf->{vcpus} || $cpus;
-    } elsif ($name eq 'max-memory') {
-       return ($conf->{memory} || $defaults->{memory}) * 1024 * 1024;
+    } elsif ($name eq 'max-memory') { # current usage maximum, not maximum hotpluggable
+       return get_current_memory($conf->{memory}) * 1024 * 1024;
     } else {
        die "unknown derived property - $name\n";
     }
index 506911e2c15cf454a68bcd46f94e95b4d9003e12..f41c61f71f3c997d874f653005890a432daa0436 100644 (file)
@@ -26,6 +26,7 @@ use PVE::QemuServer::Drive;
 use PVE::QemuServer::Helpers qw(min_version);
 use PVE::QemuServer::Machine;
 use PVE::QemuServer::Monitor qw(mon_cmd);
+use PVE::QemuServer::Memory qw(get_current_memory);
 use PVE::QemuServer;
 
 use PVE::AbstractMigrate;
@@ -1023,7 +1024,8 @@ sub phase2_start_remote_cluster {
     my $remote_vmid = $self->{opts}->{remote}->{vmid};
 
     # like regular start but with some overhead accounted for
-    my $timeout = PVE::QemuServer::Helpers::config_aware_timeout($self->{vmconf}) + 10;
+    my $memory = get_current_memory($self->{vmconf}->{memory});
+    my $timeout = PVE::QemuServer::Helpers::config_aware_timeout($self->{vmconf}, $memory) + 10;
 
     my $res = PVE::Tunnel::write_tunnel($self->{tunnel}, $timeout, "start", $params);
 
@@ -1178,7 +1180,7 @@ sub phase2 {
     $qemu_migrate_params->{'downtime-limit'} = int($migrate_downtime);
 
     # set cachesize to 10% of the total memory
-    my $memory =  $conf->{memory} || $defaults->{memory};
+    my $memory = get_current_memory($conf->{memory});
     my $cachesize = int($memory * 1048576 / 10);
     $cachesize = round_powerof2($cachesize);
 
index e4abc3868e10aadb7b57ccd34e93fedc3e396fd9..1b1ccf4d989ada27b5bbd0581aba177ea5da6fcc 100644 (file)
@@ -55,7 +55,7 @@ use PVE::QemuServer::CGroup;
 use PVE::QemuServer::CPUConfig qw(print_cpu_device get_cpu_options);
 use PVE::QemuServer::Drive qw(is_valid_drivename drive_is_cloudinit drive_is_cdrom drive_is_read_only parse_drive print_drive);
 use PVE::QemuServer::Machine;
-use PVE::QemuServer::Memory;
+use PVE::QemuServer::Memory qw(get_current_memory);
 use PVE::QemuServer::Monitor qw(mon_cmd);
 use PVE::QemuServer::PCI qw(print_pci_addr print_pcie_addr print_pcie_root_port parse_hostpci);
 use PVE::QemuServer::QMPHelpers qw(qemu_deviceadd qemu_devicedel qemu_objectadd qemu_objectdel);
@@ -350,11 +350,9 @@ my $confdesc = {
     },
     memory => {
        optional => 1,
-       type => 'integer',
-       description => "Amount of RAM for the VM in MiB. This is the maximum available memory when"
-           ." you use the balloon device.",
-       minimum => 16,
-       default => 512,
+       type => 'string',
+       description => "Memory properties.",
+       format => $PVE::QemuServer::Memory::memory_fmt
     },
     balloon => {
        optional => 1,
@@ -2903,8 +2901,7 @@ sub vmstatus {
        $d->{cpus} = $conf->{vcpus} if $conf->{vcpus};
 
        $d->{name} = $conf->{name} || "VM $vmid";
-       $d->{maxmem} = $conf->{memory} ? $conf->{memory}*(1024*1024)
-           : $defaults->{memory}*(1024*1024);
+       $d->{maxmem} = get_current_memory($conf->{memory})*(1024*1024);
 
        if ($conf->{balloon}) {
            $d->{balloon_min} = $conf->{balloon}*(1024*1024);
@@ -3849,7 +3846,7 @@ sub config_to_command {
     }
 
     PVE::QemuServer::Memory::config(
-       $conf, $vmid, $sockets, $cores, $defaults, $hotplug_features->{memory}, $cmd);
+       $conf, $vmid, $sockets, $cores, $hotplug_features->{memory}, $cmd);
 
     push @$cmd, '-S' if $conf->{freeze};
 
@@ -4987,7 +4984,7 @@ sub vmconfig_hotplug_pending {
                # enable balloon device is not hotpluggable
                die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
                # here we reset the ballooning value to memory
-               my $balloon = $conf->{memory} || $defaults->{memory};
+               my $balloon = get_current_memory($conf->{memory});
                mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
            } elsif ($fast_plug_option->{$opt}) {
                # do nothing
@@ -5000,7 +4997,7 @@ sub vmconfig_hotplug_pending {
                vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
            } elsif ($opt =~ m/^memory$/) {
                die "skip\n" if !$hotplug_features->{memory};
-               PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults);
+               PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf);
            } elsif ($opt eq 'cpuunits') {
                $cgroup->change_cpu_shares(undef);
            } elsif ($opt eq 'cpulimit') {
@@ -5055,7 +5052,8 @@ sub vmconfig_hotplug_pending {
 
                # allow manual ballooning if shares is set to zero
                if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
-                   my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
+                   my $memory = get_current_memory($conf->{memory});
+                   my $balloon = $conf->{pending}->{balloon} || $memory;
                    mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
                }
            } elsif ($opt =~ m/^net(\d+)$/) {
@@ -5075,7 +5073,7 @@ sub vmconfig_hotplug_pending {
                                     $vmid, $opt, $value, $arch, $machine_type);
            } elsif ($opt =~ m/^memory$/) { #dimms
                die "skip\n" if !$hotplug_features->{memory};
-               $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $value);
+               $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $value);
            } elsif ($opt eq 'cpuunits') {
                my $new_cpuunits = PVE::CGroup::clamp_cpu_shares($conf->{pending}->{$opt}); #clamp
                $cgroup->change_cpu_shares($new_cpuunits);
@@ -5740,7 +5738,8 @@ sub vm_start_nolock {
        push @$cmd, '-S';
     }
 
-    my $start_timeout = $params->{timeout} // config_aware_timeout($conf, $resume);
+    my $memory = get_current_memory($conf->{memory});
+    my $start_timeout = $params->{timeout} // config_aware_timeout($conf, $memory, $resume);
 
     my $pci_reserve_list = [];
     for my $device (values $pci_devices->%*) {
index 99eb33a06e5a1f1dadf615f6b8e22c92015cd28e..8817427af6eae9dcf9cb393218d21dc62e0ff3d1 100644 (file)
@@ -144,8 +144,7 @@ sub version_cmp {
 }
 
 sub config_aware_timeout {
-    my ($config, $is_suspended) = @_;
-    my $memory = $config->{memory};
+    my ($config, $memory, $is_suspended) = @_;
     my $timeout = 30;
 
     # Based on user reported startup time for vm with 512GiB @ 4-5 minutes
index 023d1a91550cce94dc727df874236f925d0d03c1..f365f2d13a852e46e5e2a786a252f09e991b04b0 100644 (file)
@@ -7,11 +7,16 @@ use PVE::JSONSchema qw(parse_property_string);
 use PVE::Tools qw(run_command lock_file lock_file_full file_read_firstline dir_glob_foreach);
 use PVE::Exception qw(raise raise_param_exc);
 
-use PVE::QemuServer;
 use PVE::QemuServer::Helpers qw(parse_number_sets);
 use PVE::QemuServer::Monitor qw(mon_cmd);
 use PVE::QemuServer::QMPHelpers qw(qemu_devicedel qemu_objectdel);
 
+use base qw(Exporter);
+
+our @EXPORT_OK = qw(
+get_current_memory
+);
+
 our $MAX_NUMA = 8;
 
 my $numa_fmt = {
@@ -59,6 +64,33 @@ sub parse_numa {
 
 my $STATICMEM = 1024;
 
+our $memory_fmt = {
+    current => {
+       description => "Current amount of online RAM for the VM in MiB. This is the maximum available memory when"
+           ." you use the balloon device.",
+       type => 'integer',
+       default_key => 1,
+       minimum => 16,
+       default => 512,
+    },
+};
+
+sub print_memory {
+    my $memory = shift;
+
+    return PVE::JSONSchema::print_property_string($memory, $memory_fmt);
+}
+
+sub parse_memory {
+    my ($value) = @_;
+
+    return { current => $memory_fmt->{current}->{default} } if !defined($value);
+
+    my $res = PVE::JSONSchema::parse_property_string($memory_fmt, $value);
+
+    return $res;
+}
+
 my $_host_bits;
 sub get_host_phys_address_bits {
     return $_host_bits if defined($_host_bits);
@@ -110,6 +142,13 @@ my sub get_max_mem {
     return $bits_to_max_mem > 4*1024*1024 ? 4*1024*1024 : $bits_to_max_mem;
 }
 
+sub get_current_memory {
+    my ($value) = @_;
+
+    my $memory = parse_memory($value);
+    return $memory->{current};
+}
+
 sub get_numa_node_list {
     my ($conf) = @_;
     my @numa_map;
@@ -174,16 +213,19 @@ sub foreach_dimm{
 }
 
 sub qemu_memory_hotplug {
-    my ($vmid, $conf, $defaults, $value) = @_;
+    my ($vmid, $conf, $value) = @_;
 
     return $value if !PVE::QemuServer::Helpers::vm_running_locally($vmid);
 
-    my $sockets = $conf->{sockets} || 1;
+    my $oldmem = parse_memory($conf->{memory});
+    my $newmem = parse_memory($value);
 
-    my $memory = $conf->{memory} || $defaults->{memory};
-    $value = $defaults->{memory} if !$value;
-    return $value if $value == $memory;
+    return $value if $newmem->{current} == $oldmem->{current};
 
+    my $memory = $oldmem->{current};
+    $value = $newmem->{current};
+
+    my $sockets = $conf->{sockets} || 1;
     my $static_memory = $STATICMEM;
     $static_memory = $static_memory * $sockets if ($conf->{hugepages} && $conf->{hugepages} == 1024);
 
@@ -198,7 +240,7 @@ sub qemu_memory_hotplug {
        foreach_dimm($conf, $vmid, $value, $static_memory, sub {
            my ($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory) = @_;
 
-               return if $current_size <= $conf->{memory};
+               return if $current_size <= get_current_memory($conf->{memory});
 
                if ($conf->{hugepages}) {
                    $numa_hostmap = get_numa_guest_to_host_map($conf) if !$numa_hostmap;
@@ -237,7 +279,8 @@ sub qemu_memory_hotplug {
                    die $err;
                }
                #update conf after each succesful module hotplug
-               $conf->{memory} = $current_size;
+               $newmem->{current} = $current_size;
+               $conf->{memory} = print_memory($newmem);
                PVE::QemuConfig->write_config($vmid, $conf);
        });
 
@@ -265,7 +308,8 @@ sub qemu_memory_hotplug {
            }
            $current_size -= $dimm_size;
            #update conf after each succesful module unplug
-           $conf->{memory} = $current_size;
+            $newmem->{current} = $current_size;
+            $conf->{memory} = print_memory($newmem);
 
            eval { qemu_objectdel($vmid, "mem-$name"); };
            PVE::QemuConfig->write_config($vmid, $conf);
@@ -292,9 +336,9 @@ sub qemu_memdevices_list {
 }
 
 sub config {
-    my ($conf, $vmid, $sockets, $cores, $defaults, $hotplug, $cmd) = @_;
+    my ($conf, $vmid, $sockets, $cores, $hotplug, $cmd) = @_;
 
-    my $memory = $conf->{memory} || $defaults->{memory};
+    my $memory = get_current_memory($conf->{memory});
     my $static_memory = 0;
 
     if ($hotplug) {
@@ -515,8 +559,7 @@ sub hugepages_topology {
 
     return if !$conf->{numa};
 
-    my $defaults = PVE::QemuServer::load_defaults();
-    my $memory = $conf->{memory} || $defaults->{memory};
+    my $memory = get_current_memory($conf->{memory});
     my $static_memory = 0;
     my $sockets = $conf->{sockets} || 1;
     my $numa_custom_topology = undef;