[pve-devel] [PATCH V2 manager] fix #4335: report: add datacenter.cfg to output
Includes the contents of /etc/pve/datacenter.cfg in the cluster section. Signed-off-by: Max Carrara --- Changes from v1: * Output of `/etc/pve/datacenter.cfg` is now in the cluster section, as discussed[1] [1] https://lists.proxmox.com/pipermail/pve-devel/2023-February/055715.html PVE/Report.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/PVE/Report.pm b/PVE/Report.pm index 90b7cb1c..457bba6e 100644 --- a/PVE/Report.pm +++ b/PVE/Report.pm @@ -91,6 +91,7 @@ my $init_report_cmds = sub { 'pvecm status', 'cat /etc/pve/corosync.conf 2>/dev/null', 'ha-manager status', + 'cat /etc/pve/datacenter.cfg', ], }, hardware => { -- 2.30.2 ___ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH qemu-server] feature #3937: config: store user in meta property
Adds a field to the "meta" config property which stores the user who created the VM. Signed-off-by: Leo Nunner --- PVE/QemuServer.pm | 8 1 file changed, 8 insertions(+) diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index a0e16dc..28ed8e7 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -281,6 +281,11 @@ my $meta_info_fmt = { pattern => '\d+(\.\d+)+', optional => 1, }, +'user' => { + type => 'string', + description => "The user who created the VM.", + optional => 1, +}, }; my $confdesc = { @@ -2184,10 +2189,13 @@ sub parse_meta_info { sub new_meta_info_string { my () = @_; # for now do not allow to override any value +my $rpcenv = PVE::RPCEnvironment->get(); + return PVE::JSONSchema::print_property_string( { 'creation-qemu' => kvm_user_version(), ctime => "". int(time()), + user => $rpcenv->get_user(), }, $meta_info_fmt ); -- 2.30.2 ___ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v2 widget-toolkit] ui: SMART: show SMART data in correct columns
Signed-off-by: Matthias Heiserer --- Changes from v2: make expression more compact src/window/DiskSmart.js | 17 ++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/window/DiskSmart.js b/src/window/DiskSmart.js index 3c8040b..b538ea1 100644 --- a/src/window/DiskSmart.js +++ b/src/window/DiskSmart.js @@ -38,12 +38,12 @@ Ext.define('Proxmox.window.DiskSmart', { }, { text: gettext('Value'), - dataIndex: 'raw', + dataIndex: 'real-value', renderer: Ext.String.htmlEncode, }, { text: gettext('Normalized'), - dataIndex: 'value', + dataIndex: 'real-normalized', width: 60, }, { @@ -154,7 +154,18 @@ Ext.define('Proxmox.window.DiskSmart', { Ext.define('pmx-smart-attribute', { extend: 'Ext.data.Model', fields: [ - { name: 'id', type: 'number' }, 'name', 'value', 'worst', 'threshold', 'flags', 'fail', 'raw', + { name: 'id', type: 'number' }, 'name', 'value', 'worst', 'threshold', 'flags', 'fail', + 'raw', 'normalized', + { + name: 'real-value', + // FIXME remove with next major release (PBS 3.0) + calculate: data => (data.normalized ?? false) ? data.raw : data.value, + }, + { + name: 'real-normalized', + // FIXME remove with next major release (PBS 3.0) + calculate: data => data.normalized ?? data.raw, + }, ], idProperty: 'name', }); -- 2.30.2 ___ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v4 qemu-server 03/16] memory: refactor sockets
Signed-off-by: Alexandre Derumier --- PVE/QemuServer/Memory.pm | 10 +++--- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/PVE/QemuServer/Memory.pm b/PVE/QemuServer/Memory.pm index e10c0b7..3899917 100644 --- a/PVE/QemuServer/Memory.pm +++ b/PVE/QemuServer/Memory.pm @@ -165,8 +165,7 @@ sub qemu_memory_hotplug { return $value if !PVE::QemuServer::check_running($vmid); -my $sockets = 1; -$sockets = $conf->{sockets} if $conf->{sockets}; +my $sockets = $conf->{sockets} || 1; my $memory = $conf->{memory} || $defaults->{memory}; $value = $defaults->{memory} if !$value; @@ -289,8 +288,7 @@ sub config { if $conf->{"numa$i"}; } - my $sockets = 1; - $sockets = $conf->{sockets} if $conf->{sockets}; + my $sockets = $conf->{sockets} || 1; $static_memory = $STATICMEM; $static_memory = $static_memory * $sockets if ($conf->{hugepages} && $conf->{hugepages} == 1024); @@ -499,9 +497,7 @@ sub hugepages_topology { my $defaults = PVE::QemuServer::load_defaults(); my $memory = $conf->{memory} || $defaults->{memory}; my $static_memory = 0; -my $sockets = 1; -$sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused -$sockets = $conf->{sockets} if $conf->{sockets}; +my $sockets = $conf->{sockets} || 1; my $numa_custom_topology = undef; my $hotplug_features = PVE::QemuServer::parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1'); -- 2.30.2 ___ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v4 qemu-server 04/16] memory: remove calls to parse_hotplug_features
Signed-off-by: Alexandre Derumier --- PVE/QemuServer.pm| 6 -- PVE/QemuServer/Memory.pm | 13 ++--- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index a0e16dc..97185e1 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -3869,7 +3869,7 @@ sub config_to_command { push @$cmd, get_cpu_options($conf, $arch, $kvm, $kvm_off, $machine_version, $winversion, $gpu_passthrough); } -PVE::QemuServer::Memory::config($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd); +PVE::QemuServer::Memory::config($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features->{memory}, $cmd); push @$cmd, '-S' if $conf->{freeze}; @@ -5902,7 +5902,9 @@ sub vm_start_nolock { if ($conf->{hugepages}) { my $code = sub { - my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf); + my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1'); + my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf, $hotplug_features->{memory}); + my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology(); PVE::QemuServer::Memory::hugepages_mount(); diff --git a/PVE/QemuServer/Memory.pm b/PVE/QemuServer/Memory.pm index 3899917..4812a9e 100644 --- a/PVE/QemuServer/Memory.pm +++ b/PVE/QemuServer/Memory.pm @@ -273,12 +273,12 @@ sub qemu_dimm_list { } sub config { -my ($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd) = @_; +my ($conf, $vmid, $sockets, $cores, $defaults, $hotplug, $cmd) = @_; my $memory = $conf->{memory} || $defaults->{memory}; my $static_memory = 0; -if ($hotplug_features->{memory}) { +if ($hotplug) { die "NUMA needs to be enabled for memory hotplug\n" if !$conf->{numa}; my $MAX_MEM = get_max_mem($conf); die "Total memory is bigger than ${MAX_MEM}MB\n" if $memory > $MAX_MEM; @@ -365,7 +365,7 @@ sub config { } } -if ($hotplug_features->{memory}) { +if ($hotplug) { foreach_dimm($conf, $vmid, $memory, $sockets, sub { my ($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory) = @_; @@ -488,7 +488,7 @@ sub hugepages_size { } sub hugepages_topology { -my ($conf) = @_; +my ($conf, $hotplug) = @_; my $hugepages_topology = {}; @@ -499,9 +499,8 @@ sub hugepages_topology { my $static_memory = 0; my $sockets = $conf->{sockets} || 1; my $numa_custom_topology = undef; -my $hotplug_features = PVE::QemuServer::parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1'); -if ($hotplug_features->{memory}) { +if ($hotplug) { $static_memory = $STATICMEM; $static_memory = $static_memory * $sockets if ($conf->{hugepages} && $conf->{hugepages} == 1024); } else { @@ -537,7 +536,7 @@ sub hugepages_topology { } } -if ($hotplug_features->{memory}) { +if ($hotplug) { my $numa_hostmap = get_numa_guest_to_host_map($conf); foreach_dimm($conf, undef, $memory, $sockets, sub { -- 2.30.2 ___ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v4 qemu-server 08/16] config: memory: add 'max' option
max can be multiple of 64GiB only, The dimm size is compute from the max memory we can have 64 slots: 64GiB = 64 slots x 1GiB 128GiB = 64 slots x 2GiB .. 4TiB = 64 slots x 64GiB Also, with numa, we need to share slot between (up to 8) sockets. 64 is a multiple of 8, 64GiB = 8 sockets * 8 slots * 1GiB 128GiB = 8 sockets * 8 slots * 2GiB ... and with virtio-mem, we can have 32000 blocks of 2MiB minimum 64GB = 32000 * 2MiB Signed-off-by: Alexandre Derumier --- PVE/QemuServer.pm| 4 ++-- PVE/QemuServer/Memory.pm | 33 + 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index f1330f1..3bd86da 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -5042,7 +5042,7 @@ sub vmconfig_hotplug_pending { vm_deviceunplug($vmid, $conf, $opt); vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force); } elsif ($opt =~ m/^memory$/) { - die "skip\n" if !$hotplug_features->{memory}; + die "skip\n" if !PVE::QemuServer::Memory::can_hotplug($hotplug_features->{memory}, $conf); PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf); } elsif ($opt eq 'cpuunits') { $cgroup->change_cpu_shares(undef); @@ -5118,7 +5118,7 @@ sub vmconfig_hotplug_pending { vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk}, $vmid, $opt, $value, $arch, $machine_type); } elsif ($opt =~ m/^memory$/) { #dimms - die "skip\n" if !$hotplug_features->{memory}; + die "skip\n" if !PVE::QemuServer::Memory::can_hotplug($hotplug_features->{memory}, $conf, $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 diff --git a/PVE/QemuServer/Memory.pm b/PVE/QemuServer/Memory.pm index 32fbdc5..deeb88f 100644 --- a/PVE/QemuServer/Memory.pm +++ b/PVE/QemuServer/Memory.pm @@ -3,8 +3,10 @@ package PVE::QemuServer::Memory; use strict; use warnings; +use PVE::JSONSchema; 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::GuestHelpers qw(safe_string_ne safe_num_ne safe_boolean_ne); use PVE::QemuServer; use PVE::QemuServer::Monitor qw(mon_cmd); @@ -25,8 +27,26 @@ our $memory_fmt = { minimum => 16, default => 512, }, +max => { + type => 'integer', + optional => 1, + minimum => 65536, + maximum => 4194304, + format => 'pve-qm-memory-max', +}, }; +PVE::JSONSchema::register_format('pve-qm-memory-max', \&verify_qm_memory_max); +sub verify_qm_memory_max { +my ($max, $noerr) = @_; + +return if $noerr; + +die "max memory need to be a multiple of 64GiB\n" if $max && $max % 65536 != 0; + +return $max +} + sub print_memory { my $memory = shift; @@ -313,6 +333,19 @@ sub qemu_memory_hotplug { return $conf->{memory}; } +sub can_hotplug { +my ($hotplug, $conf, $value) = @_; + +return if !$hotplug; + +my $oldmem = parse_memory($conf->{memory}); +my $newmem = parse_memory($value); + +return if safe_num_ne($newmem->{max}, $oldmem->{max}); + +return 1; +} + sub qemu_dimm_list { my ($vmid) = @_; -- 2.30.2 ___ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v4 qemu-server 00/16] rework memory hotplug + virtiomem
This patch series rework the current memory hotplug + virtiomem. memory option now have extra options: memory: [[current=]] [,max=] [,virtio=<1|0>] ex: memory: current=1024,max=131072,virtio=1 for classic memory hotplug, when maxmemory is defined, we use 64 fixed size dimm. The max option is a multiple of 64GB. The virtio option enable new virtio-mem support, instead of plugging dimm, it's add/removed block inside big dimm. virtio-mem can use 32000 blocks, the blocksize is compute from max memory. Changelog v2: update differents patches based on Fiona comments. (I have send 2 others mails with comments not yet addressed) Biggest change is on virtio-mem, instead of trying to have same amount of memory on each virtiomem (some block could be unmovable and break unplug), we try to balance/dispatch remaining block on other available virtiomems. Also, the minimum blocksize supported by linux guest os is 4MB currently, even if virtiomem can use 2MB on qemu side. Changelog v3: - cleanup from last Fiona comments - classic hotplug : fix memory unplug - virtio-mem: split retry logic in a second optional patch (feel free to apply it later if needed) Changelog v4: - cleanup from last Fiona comments Alexandre Derumier (16): memory: extract some code to their own sub for mocking tests: add memory tests memory: refactor sockets memory: remove calls to parse_hotplug_features add memory parser memory: add get_static_mem memory: use static_memory in foreach_dimm config: memory: add 'max' option memory: get_max_mem: use config memory max memory: rename qemu_dimm_list to qemu_memdevices_list memory: don't use foreach_reversedimm for unplug memory: use 64 slots && static dimm size when max is defined test: add memory-max tests memory: add virtio-mem support memory: virtio-mem : implement redispatch retry. tests: add virtio-mem tests PVE/API2/Qemu.pm | 38 +- PVE/QemuConfig.pm | 4 +- PVE/QemuMigrate.pm| 6 +- PVE/QemuServer.pm | 40 +- PVE/QemuServer/Helpers.pm | 3 +- PVE/QemuServer/Memory.pm | 527 ++ PVE/QemuServer/PCI.pm | 8 + test/cfg2cmd/memory-hotplug-hugepages.conf| 12 + .../cfg2cmd/memory-hotplug-hugepages.conf.cmd | 62 +++ test/cfg2cmd/memory-hotplug.conf | 11 + test/cfg2cmd/memory-hotplug.conf.cmd | 174 ++ test/cfg2cmd/memory-hugepages-1g.conf | 11 + test/cfg2cmd/memory-hugepages-1g.conf.cmd | 30 + test/cfg2cmd/memory-hugepages-2m.conf | 11 + test/cfg2cmd/memory-hugepages-2m.conf.cmd | 30 + test/cfg2cmd/memory-max-128G.conf | 11 + test/cfg2cmd/memory-max-128G.conf.cmd | 86 +++ test/cfg2cmd/memory-max-512G.conf | 11 + test/cfg2cmd/memory-max-512G.conf.cmd | 58 ++ test/cfg2cmd/memory-virtio-hugepages-1G.conf | 12 + .../memory-virtio-hugepages-1G.conf.cmd | 35 ++ test/cfg2cmd/memory-virtio-max.conf | 11 + test/cfg2cmd/memory-virtio-max.conf.cmd | 35 ++ test/cfg2cmd/memory-virtio.conf | 11 + test/cfg2cmd/memory-virtio.conf.cmd | 35 ++ test/run_config2command_tests.pl | 15 + 26 files changed, 1135 insertions(+), 152 deletions(-) create mode 100644 test/cfg2cmd/memory-hotplug-hugepages.conf create mode 100644 test/cfg2cmd/memory-hotplug-hugepages.conf.cmd create mode 100644 test/cfg2cmd/memory-hotplug.conf create mode 100644 test/cfg2cmd/memory-hotplug.conf.cmd create mode 100644 test/cfg2cmd/memory-hugepages-1g.conf create mode 100644 test/cfg2cmd/memory-hugepages-1g.conf.cmd create mode 100644 test/cfg2cmd/memory-hugepages-2m.conf create mode 100644 test/cfg2cmd/memory-hugepages-2m.conf.cmd create mode 100644 test/cfg2cmd/memory-max-128G.conf create mode 100644 test/cfg2cmd/memory-max-128G.conf.cmd create mode 100644 test/cfg2cmd/memory-max-512G.conf create mode 100644 test/cfg2cmd/memory-max-512G.conf.cmd create mode 100644 test/cfg2cmd/memory-virtio-hugepages-1G.conf create mode 100644 test/cfg2cmd/memory-virtio-hugepages-1G.conf.cmd create mode 100644 test/cfg2cmd/memory-virtio-max.conf create mode 100644 test/cfg2cmd/memory-virtio-max.conf.cmd create mode 100644 test/cfg2cmd/memory-virtio.conf create mode 100644 test/cfg2cmd/memory-virtio.conf.cmd -- 2.30.2 ___ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v4 qemu-server 11/16] memory: don't use foreach_reversedimm for unplug
simple use dimm_list() returned by qemu Signed-off-by: Alexandre Derumier --- PVE/QemuServer/Memory.pm | 73 1 file changed, 22 insertions(+), 51 deletions(-) diff --git a/PVE/QemuServer/Memory.pm b/PVE/QemuServer/Memory.pm index a13b3a1..cf1ddb9 100644 --- a/PVE/QemuServer/Memory.pm +++ b/PVE/QemuServer/Memory.pm @@ -217,38 +217,6 @@ sub foreach_dimm{ } } -sub foreach_reverse_dimm { -my ($conf, $vmid, $memory, $sockets, $func) = @_; - -my $dimm_id = 253; -my $current_size = 0; -my $dimm_size = 0; - -if($conf->{hugepages} && $conf->{hugepages} == 1024) { - $current_size = 8355840; - $dimm_size = 131072; -} else { - $current_size = 4177920; - $dimm_size = 65536; -} - -return if $current_size == $memory; - -my @numa_map = get_numa_node_list($conf); - -for (my $j = 0; $j < 8; $j++) { - for (my $i = 0; $i < 32; $i++) { - my $name = "dimm${dimm_id}"; - $dimm_id--; - my $numanode = $numa_map[(31-$i) % @numa_map]; - $current_size -= $dimm_size; - &$func($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory); - return $current_size if $current_size <= $memory; - } - $dimm_size /= 2; -} -} - sub qemu_memory_hotplug { my ($vmid, $conf, $value) = @_; @@ -322,30 +290,33 @@ sub qemu_memory_hotplug { } else { - foreach_reverse_dimm($conf, $vmid, $value, $sockets, sub { - my ($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory) = @_; + my $dimms = qemu_dimm_list($vmid); + my $current_size = $memory; + for my $name (sort { $dimms->{$b}{slot} <=> $dimms->{$a}{slot} } keys %$dimms) { - return if $current_size >= get_current_memory($conf->{memory}); + my $dimm_size = $dimms->{$name}->{size} / 1024 / 1024; - print "try to unplug memory dimm $name\n"; + last if $current_size <= $value; - my $retry = 0; - while (1) { - eval { PVE::QemuServer::qemu_devicedel($vmid, $name) }; - sleep 3; - my $dimm_list = qemu_memdevices_list($vmid, '^dimm(\d+)$'); - last if !$dimm_list->{$name}; - raise_param_exc({ $name => "error unplug memory module" }) if $retry > 5; - $retry++; - } + print "try to unplug memory dimm $name\n"; - #update conf after each succesful module unplug - $newmem->{current} = $current_size; - $conf->{memory} = print_memory($newmem); + my $retry = 0; + while (1) { + eval { PVE::QemuServer::qemu_devicedel($vmid, $name) }; + sleep 3; + my $dimm_list = qemu_memdevices_list($vmid, '^dimm(\d+)$'); + last if !$dimm_list->{$name}; + raise_param_exc({ $name => "error unplug memory module" }) if $retry > 5; + $retry++; + } + $current_size -= $dimm_size; + #update conf after each succesful module unplug + $newmem->{current} = $current_size; + $conf->{memory} = print_memory($newmem); - eval { PVE::QemuServer::qemu_objectdel($vmid, "mem-$name"); }; - PVE::QemuConfig->write_config($vmid, $conf); - }); + eval { PVE::QemuServer::qemu_objectdel($vmid, "mem-$name"); }; + PVE::QemuConfig->write_config($vmid, $conf); + } } return $conf->{memory}; } -- 2.30.2 ___ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v4 qemu-server 15/16] memory: virtio-mem : implement redispatch retry.
If some memory can be removed on a specific node, we try to rebalance again on other nodes Signed-off-by: Alexandre Derumier --- PVE/QemuServer/Memory.pm | 51 +++- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/PVE/QemuServer/Memory.pm b/PVE/QemuServer/Memory.pm index bf4e92a..f02b4e0 100644 --- a/PVE/QemuServer/Memory.pm +++ b/PVE/QemuServer/Memory.pm @@ -201,13 +201,28 @@ my sub get_virtiomem_total_current_size { return $size; } +my sub get_virtiomem_total_errors_size { +my ($mems) = @_; + +my $size = 0; +for my $mem (values %$mems) { + next if !$mem->{error}; + $size += $mem->{current}; +} +return $size; +} + my sub balance_virtiomem { my ($vmid, $virtiomems, $blocksize, $target_total) = @_; -my $nb_virtiomem = scalar(keys %$virtiomems); +my $nb_virtiomem = scalar(grep { !$_->{error} } values $virtiomems->%*); print"try to balance memory on $nb_virtiomem virtiomems\n"; +die "No more available blocks in virtiomem to balance all requested memory\n" + if $target_total < 0; +die "No more available virtiomem to balance the remaining memory\n" if $nb_virtiomem == 0; + #if we can't share exactly the same amount, we add the remainder on last node my $target_aligned = int( $target_total / $nb_virtiomem / $blocksize) * $blocksize; my $target_remaining = $target_total - ($target_aligned * ($nb_virtiomem-1)); @@ -215,6 +230,7 @@ my sub balance_virtiomem { my $i = 0; foreach my $id (sort keys %$virtiomems) { my $virtiomem = $virtiomems->{$id}; + next if $virtiomem->{error}; $i++; my $virtiomem_target = $i == $nb_virtiomem ? $target_remaining : $target_aligned; $virtiomem->{completed} = 0; @@ -229,7 +245,6 @@ my sub balance_virtiomem { } my $total_finished = 0; -my $error = undef; while ($total_finished != $nb_virtiomem) { @@ -267,7 +282,6 @@ my sub balance_virtiomem { if($virtiomem->{retry} >= 5) { print "virtiomem$id: too many retry. set error\n"; $virtiomem->{error} = 1; - $error = 1; #as change is async, we don't want that value change after the api call eval { mon_cmd($vmid, 'qom-set', @@ -280,7 +294,6 @@ my sub balance_virtiomem { $virtiomem->{retry}++; } } -die "No more available blocks in virtiomem to balance all requested memory\n" if $error; } sub get_numa_node_list { @@ -388,18 +401,24 @@ sub qemu_memory_hotplug { }; } - my $target_total = $value - $static_memory; - my $err; - eval { - balance_virtiomem($vmid, $virtiomems, $blocksize, $target_total); - }; - $err = $@ if $@; - - my $current_memory = $static_memory + get_virtiomem_total_current_size($virtiomems); - $newmem->{current} = $current_memory; - $conf->{memory} = print_memory($newmem); - PVE::QemuConfig->write_config($vmid, $conf); - die $err if $err; + while (1) { + + my $target_total = $value - $static_memory - get_virtiomem_total_errors_size($virtiomems); + my $err; + eval { + balance_virtiomem($vmid, $virtiomems, $blocksize, $target_total); + }; + $err = $@ if $@; + + my $current_memory = $static_memory + get_virtiomem_total_current_size($virtiomems); + $newmem->{current} = $current_memory; + $conf->{memory} = print_memory($newmem); + PVE::QemuConfig->write_config($vmid, $conf); + + die $err if $err; + last if $current_memory == $value; + } + return $conf->{memory}; } elsif ($value > $memory) { -- 2.30.2 ___ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v4 qemu-server 05/16] add memory parser
Signed-off-by: Alexandre Derumier --- PVE/API2/Qemu.pm | 7 ++-- PVE/QemuConfig.pm | 4 +-- PVE/QemuMigrate.pm| 6 ++-- PVE/QemuServer.pm | 27 +++ PVE/QemuServer/Helpers.pm | 3 +- PVE/QemuServer/Memory.pm | 71 --- 6 files changed, 82 insertions(+), 36 deletions(-) diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm index 587bb22..9b80da1 100644 --- a/PVE/API2/Qemu.pm +++ b/PVE/API2/Qemu.pm @@ -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::QemuMigrate; use PVE::RPCEnvironment; use PVE::AccessControl; @@ -1489,8 +1490,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 @@ -1608,7 +1607,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" diff --git a/PVE/QemuConfig.pm b/PVE/QemuConfig.pm index 051382c..999e658 100644 --- a/PVE/QemuConfig.pm +++ b/PVE/QemuConfig.pm @@ -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 diff --git a/PVE/QemuMigrate.pm b/PVE/QemuMigrate.pm index 09cc1d8..f86fdbe 100644 --- a/PVE/QemuMigrate.pm +++ b/PVE/QemuMigrate.pm @@ -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; @@ -1026,7 +1027,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); @@ -1181,7 +1183,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); diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index 97185e1..f1330f1 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -53,7 +53,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::USB qw(parse_usb_device); @@ -341,11 +341,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 => { o
[pve-devel] [PATCH v4 qemu-server 13/16] test: add memory-max tests
Signed-off-by: Alexandre Derumier --- test/cfg2cmd/memory-max-128G.conf | 11 test/cfg2cmd/memory-max-128G.conf.cmd | 86 +++ test/cfg2cmd/memory-max-512G.conf | 11 test/cfg2cmd/memory-max-512G.conf.cmd | 58 ++ 4 files changed, 166 insertions(+) create mode 100644 test/cfg2cmd/memory-max-128G.conf create mode 100644 test/cfg2cmd/memory-max-128G.conf.cmd create mode 100644 test/cfg2cmd/memory-max-512G.conf create mode 100644 test/cfg2cmd/memory-max-512G.conf.cmd diff --git a/test/cfg2cmd/memory-max-128G.conf b/test/cfg2cmd/memory-max-128G.conf new file mode 100644 index 000..8f0328d --- /dev/null +++ b/test/cfg2cmd/memory-max-128G.conf @@ -0,0 +1,11 @@ +# TEST: memorymax 64G with 2 socket, dimm size should be 1GB && static memory should be 4G +# QEMU_VERSION: 7.2 +cores: 2 +memory: 32768,max=65536 +name: simple +numa: 1 +ostype: l26 +smbios1: uuid=7b10d7af-b932-4c66-b2c3-3996152ec465 +sockets: 2 +vmgenid: c773c261-d800-4348-9f5d-167fadd53cf8 +hotplug: memory \ No newline at end of file diff --git a/test/cfg2cmd/memory-max-128G.conf.cmd b/test/cfg2cmd/memory-max-128G.conf.cmd new file mode 100644 index 000..5b22027 --- /dev/null +++ b/test/cfg2cmd/memory-max-128G.conf.cmd @@ -0,0 +1,86 @@ +/usr/bin/kvm \ + -id 8006 \ + -name 'simple,debug-threads=on' \ + -no-shutdown \ + -chardev 'socket,id=qmp,path=/var/run/qemu-server/8006.qmp,server=on,wait=off' \ + -mon 'chardev=qmp,mode=control' \ + -chardev 'socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5' \ + -mon 'chardev=qmp-event,mode=control' \ + -pidfile /var/run/qemu-server/8006.pid \ + -daemonize \ + -smbios 'type=1,uuid=7b10d7af-b932-4c66-b2c3-3996152ec465' \ + -smp '4,sockets=2,cores=2,maxcpus=4' \ + -nodefaults \ + -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \ + -vnc 'unix:/var/run/qemu-server/8006.vnc,password=on' \ + -cpu kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep \ + -m 'size=4096,slots=64,maxmem=65536M' \ + -object 'memory-backend-ram,id=ram-node0,size=2048M' \ + -numa 'node,nodeid=0,cpus=0-1,memdev=ram-node0' \ + -object 'memory-backend-ram,id=ram-node1,size=2048M' \ + -numa 'node,nodeid=1,cpus=2-3,memdev=ram-node1' \ + -object 'memory-backend-ram,id=mem-dimm0,size=1024M' \ + -device 'pc-dimm,id=dimm0,memdev=mem-dimm0,node=0' \ + -object 'memory-backend-ram,id=mem-dimm1,size=1024M' \ + -device 'pc-dimm,id=dimm1,memdev=mem-dimm1,node=1' \ + -object 'memory-backend-ram,id=mem-dimm2,size=1024M' \ + -device 'pc-dimm,id=dimm2,memdev=mem-dimm2,node=0' \ + -object 'memory-backend-ram,id=mem-dimm3,size=1024M' \ + -device 'pc-dimm,id=dimm3,memdev=mem-dimm3,node=1' \ + -object 'memory-backend-ram,id=mem-dimm4,size=1024M' \ + -device 'pc-dimm,id=dimm4,memdev=mem-dimm4,node=0' \ + -object 'memory-backend-ram,id=mem-dimm5,size=1024M' \ + -device 'pc-dimm,id=dimm5,memdev=mem-dimm5,node=1' \ + -object 'memory-backend-ram,id=mem-dimm6,size=1024M' \ + -device 'pc-dimm,id=dimm6,memdev=mem-dimm6,node=0' \ + -object 'memory-backend-ram,id=mem-dimm7,size=1024M' \ + -device 'pc-dimm,id=dimm7,memdev=mem-dimm7,node=1' \ + -object 'memory-backend-ram,id=mem-dimm8,size=1024M' \ + -device 'pc-dimm,id=dimm8,memdev=mem-dimm8,node=0' \ + -object 'memory-backend-ram,id=mem-dimm9,size=1024M' \ + -device 'pc-dimm,id=dimm9,memdev=mem-dimm9,node=1' \ + -object 'memory-backend-ram,id=mem-dimm10,size=1024M' \ + -device 'pc-dimm,id=dimm10,memdev=mem-dimm10,node=0' \ + -object 'memory-backend-ram,id=mem-dimm11,size=1024M' \ + -device 'pc-dimm,id=dimm11,memdev=mem-dimm11,node=1' \ + -object 'memory-backend-ram,id=mem-dimm12,size=1024M' \ + -device 'pc-dimm,id=dimm12,memdev=mem-dimm12,node=0' \ + -object 'memory-backend-ram,id=mem-dimm13,size=1024M' \ + -device 'pc-dimm,id=dimm13,memdev=mem-dimm13,node=1' \ + -object 'memory-backend-ram,id=mem-dimm14,size=1024M' \ + -device 'pc-dimm,id=dimm14,memdev=mem-dimm14,node=0' \ + -object 'memory-backend-ram,id=mem-dimm15,size=1024M' \ + -device 'pc-dimm,id=dimm15,memdev=mem-dimm15,node=1' \ + -object 'memory-backend-ram,id=mem-dimm16,size=1024M' \ + -device 'pc-dimm,id=dimm16,memdev=mem-dimm16,node=0' \ + -object 'memory-backend-ram,id=mem-dimm17,size=1024M' \ + -device 'pc-dimm,id=dimm17,memdev=mem-dimm17,node=1' \ + -object 'memory-backend-ram,id=mem-dimm18,size=1024M' \ + -device 'pc-dimm,id=dimm18,memdev=mem-dimm18,node=0' \ + -object 'memory-backend-ram,id=mem-dimm19,size=1024M' \ + -device 'pc-dimm,id=dimm19,memdev=mem-dimm19,node=1' \ + -object 'memory-backend-ram,id=mem-dimm20,size=1024M' \ + -device 'pc-dimm,id=dimm20,memdev=mem-dimm20,node=0' \ + -object 'memory-backend-ram,id=mem-dimm21,size=1024M' \ + -device 'pc-dimm,id=dimm21,memdev=mem-dimm21,node=1' \ + -object 'memory-backend-ram,id=mem-dimm22,size=1024M' \ + -device 'pc-dimm,id=dimm22,memdev=mem-dimm22,node=0' \ + -object 'memory-backend-ram,id=mem-dimm23,size=1024M' \
[pve-devel] [PATCH v4 qemu-server 02/16] tests: add memory tests
Signed-off-by: Alexandre Derumier --- test/cfg2cmd/memory-hotplug-hugepages.conf| 12 ++ .../cfg2cmd/memory-hotplug-hugepages.conf.cmd | 62 +++ test/cfg2cmd/memory-hotplug.conf | 11 ++ test/cfg2cmd/memory-hotplug.conf.cmd | 174 ++ test/cfg2cmd/memory-hugepages-1g.conf | 11 ++ test/cfg2cmd/memory-hugepages-1g.conf.cmd | 30 +++ test/cfg2cmd/memory-hugepages-2m.conf | 11 ++ test/cfg2cmd/memory-hugepages-2m.conf.cmd | 30 +++ test/run_config2command_tests.pl | 15 ++ 9 files changed, 356 insertions(+) create mode 100644 test/cfg2cmd/memory-hotplug-hugepages.conf create mode 100644 test/cfg2cmd/memory-hotplug-hugepages.conf.cmd create mode 100644 test/cfg2cmd/memory-hotplug.conf create mode 100644 test/cfg2cmd/memory-hotplug.conf.cmd create mode 100644 test/cfg2cmd/memory-hugepages-1g.conf create mode 100644 test/cfg2cmd/memory-hugepages-1g.conf.cmd create mode 100644 test/cfg2cmd/memory-hugepages-2m.conf create mode 100644 test/cfg2cmd/memory-hugepages-2m.conf.cmd diff --git a/test/cfg2cmd/memory-hotplug-hugepages.conf b/test/cfg2cmd/memory-hotplug-hugepages.conf new file mode 100644 index 000..6cba31e --- /dev/null +++ b/test/cfg2cmd/memory-hotplug-hugepages.conf @@ -0,0 +1,12 @@ +# TEST: memory hotplug with 1GB hugepage +# QEMU_VERSION: 3.0 +cores: 2 +memory: 18432 +name: simple +numa: 1 +ostype: l26 +smbios1: uuid=7b10d7af-b932-4c66-b2c3-3996152ec465 +sockets: 2 +vmgenid: c773c261-d800-4348-9f5d-167fadd53cf8 +hotplug: memory +hugepages: 1024 \ No newline at end of file diff --git a/test/cfg2cmd/memory-hotplug-hugepages.conf.cmd b/test/cfg2cmd/memory-hotplug-hugepages.conf.cmd new file mode 100644 index 000..6d4d8e8 --- /dev/null +++ b/test/cfg2cmd/memory-hotplug-hugepages.conf.cmd @@ -0,0 +1,62 @@ +/usr/bin/kvm \ + -id 8006 \ + -name 'simple,debug-threads=on' \ + -no-shutdown \ + -chardev 'socket,id=qmp,path=/var/run/qemu-server/8006.qmp,server=on,wait=off' \ + -mon 'chardev=qmp,mode=control' \ + -chardev 'socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5' \ + -mon 'chardev=qmp-event,mode=control' \ + -pidfile /var/run/qemu-server/8006.pid \ + -daemonize \ + -smbios 'type=1,uuid=7b10d7af-b932-4c66-b2c3-3996152ec465' \ + -smp '4,sockets=2,cores=2,maxcpus=4' \ + -nodefaults \ + -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \ + -vnc 'unix:/var/run/qemu-server/8006.vnc,password=on' \ + -cpu kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep \ + -m 'size=2048,slots=255,maxmem=524288M' \ + -object 'memory-backend-file,id=ram-node0,size=1024M,mem-path=/run/hugepages/kvm/1048576kB,share=on,prealloc=yes' \ + -numa 'node,nodeid=0,cpus=0-1,memdev=ram-node0' \ + -object 'memory-backend-file,id=ram-node1,size=1024M,mem-path=/run/hugepages/kvm/1048576kB,share=on,prealloc=yes' \ + -numa 'node,nodeid=1,cpus=2-3,memdev=ram-node1' \ + -object 'memory-backend-file,id=mem-dimm0,size=1024M,mem-path=/run/hugepages/kvm/1048576kB,share=on,prealloc=yes' \ + -device 'pc-dimm,id=dimm0,memdev=mem-dimm0,node=0' \ + -object 'memory-backend-file,id=mem-dimm1,size=1024M,mem-path=/run/hugepages/kvm/1048576kB,share=on,prealloc=yes' \ + -device 'pc-dimm,id=dimm1,memdev=mem-dimm1,node=1' \ + -object 'memory-backend-file,id=mem-dimm2,size=1024M,mem-path=/run/hugepages/kvm/1048576kB,share=on,prealloc=yes' \ + -device 'pc-dimm,id=dimm2,memdev=mem-dimm2,node=0' \ + -object 'memory-backend-file,id=mem-dimm3,size=1024M,mem-path=/run/hugepages/kvm/1048576kB,share=on,prealloc=yes' \ + -device 'pc-dimm,id=dimm3,memdev=mem-dimm3,node=1' \ + -object 'memory-backend-file,id=mem-dimm4,size=1024M,mem-path=/run/hugepages/kvm/1048576kB,share=on,prealloc=yes' \ + -device 'pc-dimm,id=dimm4,memdev=mem-dimm4,node=0' \ + -object 'memory-backend-file,id=mem-dimm5,size=1024M,mem-path=/run/hugepages/kvm/1048576kB,share=on,prealloc=yes' \ + -device 'pc-dimm,id=dimm5,memdev=mem-dimm5,node=1' \ + -object 'memory-backend-file,id=mem-dimm6,size=1024M,mem-path=/run/hugepages/kvm/1048576kB,share=on,prealloc=yes' \ + -device 'pc-dimm,id=dimm6,memdev=mem-dimm6,node=0' \ + -object 'memory-backend-file,id=mem-dimm7,size=1024M,mem-path=/run/hugepages/kvm/1048576kB,share=on,prealloc=yes' \ + -device 'pc-dimm,id=dimm7,memdev=mem-dimm7,node=1' \ + -object 'memory-backend-file,id=mem-dimm8,size=1024M,mem-path=/run/hugepages/kvm/1048576kB,share=on,prealloc=yes' \ + -device 'pc-dimm,id=dimm8,memdev=mem-dimm8,node=0' \ + -object 'memory-backend-file,id=mem-dimm9,size=1024M,mem-path=/run/hugepages/kvm/1048576kB,share=on,prealloc=yes' \ + -device 'pc-dimm,id=dimm9,memdev=mem-dimm9,node=1' \ + -object 'memory-backend-file,id=mem-dimm10,size=1024M,mem-path=/run/hugepages/kvm/1048576kB,share=on,prealloc=yes' \ + -device 'pc-dimm,id=dimm10,memdev=mem-dimm10,node=0' \ + -object 'memory-backend-file,id=mem-dimm11,size=1024M,mem-path=/run/hugepages
[pve-devel] [PATCH v4 qemu-server 01/16] memory: extract some code to their own sub for mocking
Signed-off-by: Alexandre Derumier --- PVE/QemuServer/Memory.pm | 27 +++ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/PVE/QemuServer/Memory.pm b/PVE/QemuServer/Memory.pm index 6fac468..e10c0b7 100644 --- a/PVE/QemuServer/Memory.pm +++ b/PVE/QemuServer/Memory.pm @@ -13,7 +13,7 @@ my $MAX_NUMA = 8; my $STATICMEM = 1024; my $_host_bits; -my sub get_host_phys_address_bits { +sub get_host_phys_address_bits { return $_host_bits if defined($_host_bits); my $fh = IO::File->new ('/proc/cpuinfo', "r") or return; @@ -76,6 +76,12 @@ sub get_numa_node_list { return (0..($sockets-1)); } +sub host_numanode_exists { +my ($id) = @_; + +return -d "/sys/devices/system/node/node$id/"; +} + # only valid when numa nodes map to a single host node sub get_numa_guest_to_host_map { my ($conf) = @_; @@ -348,7 +354,7 @@ sub config { my $numa_memory = ($static_memory / $sockets); for (my $i = 0; $i < $sockets; $i++) { - die "host NUMA node$i doesn't exist\n" if ! -d "/sys/devices/system/node/node$i/" && $conf->{hugepages}; + die "host NUMA node$i doesn't exist\n" if !host_numanode_exists($i) && $conf->{hugepages}; my $mem_object = print_mem_object($conf, "ram-node$i", $numa_memory); push @$cmd, '-object', $mem_object; @@ -402,7 +408,7 @@ sub print_numa_hostnodes { $hostnodes .= "-$end" if defined($end); $end //= $start; for (my $i = $start; $i <= $end; ++$i ) { - die "host NUMA node$i doesn't exist\n" if ! -d "/sys/devices/system/node/node$i/"; + die "host NUMA node$i doesn't exist\n" if !host_numanode_exists($i); } } return $hostnodes; @@ -445,21 +451,26 @@ sub hugepages_nr { return $size / $hugepages_size; } +sub hugepages_chunk_size_supported { +my ($size) = @_; + +return -d "/sys/kernel/mm/hugepages/hugepages-". ($size * 1024) ."kB"; +} + sub hugepages_size { my ($conf, $size) = @_; die "hugepages option is not enabled" if !$conf->{hugepages}; die "memory size '$size' is not a positive even integer; cannot use for hugepages\n" if $size <= 0 || $size & 1; -my $page_chunk = sub { -d "/sys/kernel/mm/hugepages/hugepages-". ($_[0] * 1024) ."kB" }; -die "your system doesn't support hugepages\n" if !$page_chunk->(2) && !$page_chunk->(1024); +die "your system doesn't support hugepages\n" if !hugepages_chunk_size_supported(2) && !hugepages_chunk_size_supported(1024); if ($conf->{hugepages} eq 'any') { # try to use 1GB if available && memory size is matching - if ($page_chunk->(1024) && ($size & 1023) == 0) { + if (hugepages_chunk_size_supported(1024) && ($size & 1023) == 0) { return 1024; - } elsif ($page_chunk->(2)) { + } elsif (hugepages_chunk_size_supported(2)) { return 2; } else { die "host only supports 1024 GB hugepages, but requested size '$size' is not a multiple of 1024 MB\n" @@ -468,7 +479,7 @@ sub hugepages_size { my $hugepagesize = $conf->{hugepages}; - if (!$page_chunk->($hugepagesize)) { + if (!hugepages_chunk_size_supported($hugepagesize)) { die "your system doesn't support hugepages of $hugepagesize MB\n"; } elsif (($size % $hugepagesize) != 0) { die "Memory size $size is not a multiple of the requested hugepages size $hugepagesize\n"; -- 2.30.2 ___ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v4 qemu-server 14/16] memory: add virtio-mem support
a 4GiB static memory is needed for DMA+boot memory, as this memory is almost always un-unpluggeable. 1 virtio-mem pci device is setup for each numa node on pci.4 bridge virtio-mem use a fixed blocksize with 32000 blocks Blocksize is computed from the maxmemory-4096/32000 with a minimum of 2MiB to map THP. (lower blocksize = more chance to unplug memory). Note: Currently, linux only support 4MiB virtio blocksize, 2MiB support is currently is progress. For hotplug/unplug, we are try to allocate/unallocate same amount of memory aligned to the blocksize on each numa node if possible. If a node a not able to reach the target memory (could be an unmovable page on unplug for example), we try again to redispatch memory the remaining memory on others nodes. About hugepages: For ordinary memory devices, such as DIMMs, we preallocate memory via the memory backend for such use cases; however, with virtio-mem we're dealing with sparse memory backends; preallocating the whole memory backend destroys the whole purpose of virtio-mem. Instead, we want to preallocate memory when actually exposing memory to the VM dynamically, and fail plugging memory gracefully + warn the user in case preallocation fails. fixes: https://bugzilla.proxmox.com/show_bug.cgi?id=2949 Signed-off-by: Alexandre Derumier --- PVE/API2/Qemu.pm | 9 +- PVE/QemuServer.pm| 7 +- PVE/QemuServer/Memory.pm | 215 --- PVE/QemuServer/PCI.pm| 8 ++ 4 files changed, 222 insertions(+), 17 deletions(-) diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm index 6627910..7a2128a 100644 --- a/PVE/API2/Qemu.pm +++ b/PVE/API2/Qemu.pm @@ -32,7 +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 parse_memory get_host_max_mem); +use PVE::QemuServer::Memory qw(get_current_memory parse_memory get_host_max_mem get_virtiomem_block_size); use PVE::QemuMigrate; use PVE::RPCEnvironment; use PVE::AccessControl; @@ -485,6 +485,13 @@ my $check_memory_param = sub { die "memory max can't be bigger than supported cpu architecture $host_max_mem MiB\n" if $mem->{max} && $mem->{max} > $host_max_mem; +if ($mem->{virtio}) { + my $blocksize = get_virtiomem_block_size($conf); + + die "memory need to be a multiple of $blocksize MiB when virtiomem is enabled\n" + if $mem->{current} % $blocksize != 0; +} + if ($param->{memory} || defined($param->{balloon})) { my $memory = $param->{memory} || $conf->{pending}->{memory} || $conf->{memory}; diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm index 3bd86da..a34ff3e 100644 --- a/PVE/QemuServer.pm +++ b/PVE/QemuServer.pm @@ -3866,7 +3866,12 @@ sub config_to_command { push @$cmd, get_cpu_options($conf, $arch, $kvm, $kvm_off, $machine_version, $winversion, $gpu_passthrough); } -PVE::QemuServer::Memory::config($conf, $vmid, $sockets, $cores, $hotplug_features->{memory}, $cmd); +my $mem_devices = {}; +PVE::QemuServer::Memory::config($conf, $vmid, $sockets, $cores, $hotplug_features->{memory}, $cmd, $mem_devices); +foreach my $id (sort keys %$mem_devices) { + my $pciaddr = print_pci_addr($id, $bridges, $arch, $machine_type); + push @$devices, "-device", "$mem_devices->{$id}$pciaddr"; +} push @$cmd, '-S' if $conf->{freeze}; diff --git a/PVE/QemuServer/Memory.pm b/PVE/QemuServer/Memory.pm index 1b1c99d..bf4e92a 100644 --- a/PVE/QemuServer/Memory.pm +++ b/PVE/QemuServer/Memory.pm @@ -3,6 +3,8 @@ package PVE::QemuServer::Memory; use strict; use warnings; +use POSIX qw(ceil); + use PVE::JSONSchema; 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); @@ -16,6 +18,7 @@ our @EXPORT_OK = qw( get_current_memory parse_memory get_host_max_mem +get_virtiomem_block_size ); my $MAX_NUMA = 8; @@ -37,6 +40,12 @@ our $memory_fmt = { maximum => 4194304, format => 'pve-qm-memory-max', }, +virtio => { + description => "Enable virtio-mem memory (Experimental: Only works with Linux guest with kernel >= 5.10)", + type => 'boolean', + optional => 1, + default => 0, +}, }; PVE::JSONSchema::register_format('pve-qm-memory-max', \&verify_qm_memory_max); @@ -72,7 +81,9 @@ my sub get_static_mem { my $static_memory = 0; my $memory = parse_memory($conf->{memory}); -if ($memory->{max}) { +if ($memory->{virtio}) { + $static_memory = 4096; +} elsif ($memory->{max}) { my $dimm_size = $memory->{max} / $MAX_SLOTS; #static mem can't be lower than 4G and lower than 1 dimmsize by socket $static_memory = $dimm_size * $sockets; @@ -161,6 +172,117 @@ sub get_current_memory { return $memory->{current}; } +sub get_virtiomem_block_size { +my ($con
[pve-devel] [PATCH v4 qemu-server 16/16] tests: add virtio-mem tests
Signed-off-by: Alexandre Derumier --- test/cfg2cmd/memory-virtio-hugepages-1G.conf | 12 +++ .../memory-virtio-hugepages-1G.conf.cmd | 35 +++ test/cfg2cmd/memory-virtio-max.conf | 11 ++ test/cfg2cmd/memory-virtio-max.conf.cmd | 35 +++ test/cfg2cmd/memory-virtio.conf | 11 ++ test/cfg2cmd/memory-virtio.conf.cmd | 35 +++ 6 files changed, 139 insertions(+) create mode 100644 test/cfg2cmd/memory-virtio-hugepages-1G.conf create mode 100644 test/cfg2cmd/memory-virtio-hugepages-1G.conf.cmd create mode 100644 test/cfg2cmd/memory-virtio-max.conf create mode 100644 test/cfg2cmd/memory-virtio-max.conf.cmd create mode 100644 test/cfg2cmd/memory-virtio.conf create mode 100644 test/cfg2cmd/memory-virtio.conf.cmd diff --git a/test/cfg2cmd/memory-virtio-hugepages-1G.conf b/test/cfg2cmd/memory-virtio-hugepages-1G.conf new file mode 100644 index 000..bbe908c --- /dev/null +++ b/test/cfg2cmd/memory-virtio-hugepages-1G.conf @@ -0,0 +1,12 @@ +# TEST: virtio-mem without memorymax defined and hugepages +# QEMU_VERSION: 7.2 +cores: 2 +memory: 32768,virtio=1 +name: simple +numa: 1 +ostype: l26 +smbios1: uuid=7b10d7af-b932-4c66-b2c3-3996152ec465 +sockets: 2 +vmgenid: c773c261-d800-4348-9f5d-167fadd53cf8 +hugepages: 1024 +hotplug: memory \ No newline at end of file diff --git a/test/cfg2cmd/memory-virtio-hugepages-1G.conf.cmd b/test/cfg2cmd/memory-virtio-hugepages-1G.conf.cmd new file mode 100644 index 000..2e7de74 --- /dev/null +++ b/test/cfg2cmd/memory-virtio-hugepages-1G.conf.cmd @@ -0,0 +1,35 @@ +/usr/bin/kvm \ + -id 8006 \ + -name 'simple,debug-threads=on' \ + -no-shutdown \ + -chardev 'socket,id=qmp,path=/var/run/qemu-server/8006.qmp,server=on,wait=off' \ + -mon 'chardev=qmp,mode=control' \ + -chardev 'socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5' \ + -mon 'chardev=qmp-event,mode=control' \ + -pidfile /var/run/qemu-server/8006.pid \ + -daemonize \ + -smbios 'type=1,uuid=7b10d7af-b932-4c66-b2c3-3996152ec465' \ + -smp '4,sockets=2,cores=2,maxcpus=4' \ + -nodefaults \ + -boot 'menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg' \ + -vnc 'unix:/var/run/qemu-server/8006.vnc,password=on' \ + -cpu kvm64,enforce,+kvm_pv_eoi,+kvm_pv_unhalt,+lahf_lm,+sep \ + -m 'size=4096,maxmem=524288M' \ + -object 'memory-backend-file,id=ram-node0,size=2048M,mem-path=/run/hugepages/kvm/1048576kB,share=on' \ + -numa 'node,nodeid=0,cpus=0-1,memdev=ram-node0' \ + -object 'memory-backend-file,id=ram-node1,size=2048M,mem-path=/run/hugepages/kvm/1048576kB,share=on' \ + -numa 'node,nodeid=1,cpus=2-3,memdev=ram-node1' \ + -object 'memory-backend-file,id=mem-virtiomem0,size=260096M,mem-path=/run/hugepages/kvm/1048576kB,share=on,reserve=off' \ + -object 'memory-backend-file,id=mem-virtiomem1,size=260096M,mem-path=/run/hugepages/kvm/1048576kB,share=on,reserve=off' \ + -device 'pci-bridge,id=pci.1,chassis_nr=1,bus=pci.0,addr=0x1e' \ + -device 'pci-bridge,id=pci.2,chassis_nr=2,bus=pci.0,addr=0x1f' \ + -device 'pci-bridge,id=pci.4,chassis_nr=4,bus=pci.1,addr=0x1c' \ + -device 'vmgenid,guid=c773c261-d800-4348-9f5d-167fadd53cf8' \ + -device 'piix3-usb-uhci,id=uhci,bus=pci.0,addr=0x1.0x2' \ + -device 'usb-tablet,id=tablet,bus=uhci.0,port=1' \ + -device 'VGA,id=vga,bus=pci.0,addr=0x2' \ + -device 'virtio-mem-pci,block-size=32M,requested-size=14336M,id=virtiomem0,memdev=mem-virtiomem0,node=0,prealloc=on,bus=pci.4,addr=0x4' \ + -device 'virtio-mem-pci,block-size=32M,requested-size=14336M,id=virtiomem1,memdev=mem-virtiomem1,node=1,prealloc=on,bus=pci.4,addr=0x5' \ + -device 'virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3,free-page-reporting=on' \ + -iscsi 'initiator-name=iqn.1993-08.org.debian:01:aabbccddeeff' \ + -machine 'type=pc+pve0' \ No newline at end of file diff --git a/test/cfg2cmd/memory-virtio-max.conf b/test/cfg2cmd/memory-virtio-max.conf new file mode 100644 index 000..59b8e94 --- /dev/null +++ b/test/cfg2cmd/memory-virtio-max.conf @@ -0,0 +1,11 @@ +# TEST: memory max 64G with 2 socket with virtio-mem +# QEMU_VERSION: 7.2 +cores: 2 +memory: 32768,max=65536,virtio=1 +name: simple +numa: 1 +ostype: l26 +smbios1: uuid=7b10d7af-b932-4c66-b2c3-3996152ec465 +sockets: 2 +vmgenid: c773c261-d800-4348-9f5d-167fadd53cf8 +hotplug: memory \ No newline at end of file diff --git a/test/cfg2cmd/memory-virtio-max.conf.cmd b/test/cfg2cmd/memory-virtio-max.conf.cmd new file mode 100644 index 000..6bda268 --- /dev/null +++ b/test/cfg2cmd/memory-virtio-max.conf.cmd @@ -0,0 +1,35 @@ +/usr/bin/kvm \ + -id 8006 \ + -name 'simple,debug-threads=on' \ + -no-shutdown \ + -chardev 'socket,id=qmp,path=/var/run/qemu-server/8006.qmp,server=on,wait=off' \ + -mon 'chardev=qmp,mode=control' \ + -chardev 'socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5' \ + -mon 'chardev=qmp-event,mode=control' \ + -pidfile /var/run/qemu-server/8006.pid \
[pve-devel] [PATCH v4 qemu-server 06/16] memory: add get_static_mem
Signed-off-by: Alexandre Derumier --- PVE/QemuServer/Memory.pm | 37 +++-- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/PVE/QemuServer/Memory.pm b/PVE/QemuServer/Memory.pm index 09fa25c..5dc2cb8 100644 --- a/PVE/QemuServer/Memory.pm +++ b/PVE/QemuServer/Memory.pm @@ -15,7 +15,6 @@ get_current_memory ); my $MAX_NUMA = 8; -my $STATICMEM = 1024; our $memory_fmt = { current => { @@ -44,6 +43,22 @@ sub parse_memory { return $res; } +my sub get_static_mem { +my ($conf, $sockets, $hotplug) = @_; + +my $static_memory = 0; +my $memory = parse_memory($conf->{memory}); + +if ($hotplug) { + $static_memory = 1024; + $static_memory = $static_memory * $sockets if ($conf->{hugepages} && $conf->{hugepages} == 1024); +} else { + $static_memory = $memory->{current}; +} + +return $static_memory; +} + my $_host_bits; sub get_host_phys_address_bits { return $_host_bits if defined($_host_bits); @@ -213,8 +228,7 @@ sub qemu_memory_hotplug { $value = $newmem->{current}; my $sockets = $conf->{sockets} || 1; -my $static_memory = $STATICMEM; -$static_memory = $static_memory * $sockets if ($conf->{hugepages} && $conf->{hugepages} == 1024); +my $static_memory = get_static_mem($conf, $sockets, 1); die "memory can't be lower than $static_memory MB" if $value < $static_memory; my $MAX_MEM = get_max_mem($conf); @@ -322,7 +336,7 @@ sub config { my ($conf, $vmid, $sockets, $cores, $hotplug, $cmd) = @_; my $memory = get_current_memory($conf->{memory}); -my $static_memory = 0; +my $static_memory = get_static_mem($conf, $sockets, $hotplug); if ($hotplug) { die "NUMA needs to be enabled for memory hotplug\n" if !$conf->{numa}; @@ -334,17 +348,11 @@ sub config { if $conf->{"numa$i"}; } - my $sockets = $conf->{sockets} || 1; - - $static_memory = $STATICMEM; - $static_memory = $static_memory * $sockets if ($conf->{hugepages} && $conf->{hugepages} == 1024); - die "minimum memory must be ${static_memory}MB\n" if($memory < $static_memory); push @$cmd, '-m', "size=${static_memory},slots=255,maxmem=${MAX_MEM}M"; } else { - $static_memory = $memory; push @$cmd, '-m', $static_memory; } @@ -541,17 +549,10 @@ sub hugepages_topology { return if !$conf->{numa}; my $memory = get_current_memory($conf->{memory}); -my $static_memory = 0; my $sockets = $conf->{sockets} || 1; +my $static_memory = get_static_mem($conf, $sockets, $hotplug); my $numa_custom_topology = undef; -if ($hotplug) { - $static_memory = $STATICMEM; - $static_memory = $static_memory * $sockets if ($conf->{hugepages} && $conf->{hugepages} == 1024); -} else { - $static_memory = $memory; -} - #custom numa topology for (my $i = 0; $i < $MAX_NUMA; $i++) { next if !$conf->{"numa$i"}; -- 2.30.2 ___ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v4 qemu-server 10/16] memory: rename qemu_dimm_list to qemu_memdevices_list
current qemu_dimm_list can return any kind of memory devices. make it more generic, with a regex filter to choose kind of device from id. Signed-off-by: Alexandre Derumier --- PVE/QemuServer/Memory.pm | 8 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/PVE/QemuServer/Memory.pm b/PVE/QemuServer/Memory.pm index c912e4f..a13b3a1 100644 --- a/PVE/QemuServer/Memory.pm +++ b/PVE/QemuServer/Memory.pm @@ -333,7 +333,7 @@ sub qemu_memory_hotplug { while (1) { eval { PVE::QemuServer::qemu_devicedel($vmid, $name) }; sleep 3; - my $dimm_list = qemu_dimm_list($vmid); + my $dimm_list = qemu_memdevices_list($vmid, '^dimm(\d+)$'); last if !$dimm_list->{$name}; raise_param_exc({ $name => "error unplug memory module" }) if $retry > 5; $retry++; @@ -363,14 +363,14 @@ sub can_hotplug { return 1; } -sub qemu_dimm_list { -my ($vmid) = @_; +sub qemu_memdevices_list { +my ($vmid, $filter) = @_; my $dimmarray = mon_cmd($vmid, "query-memory-devices"); my $dimms = {}; foreach my $dimm (@$dimmarray) { - +next if $filter && $dimm->{data}->{id} !~ /$filter/; $dimms->{$dimm->{data}->{id}}->{id} = $dimm->{data}->{id}; $dimms->{$dimm->{data}->{id}}->{node} = $dimm->{data}->{node}; $dimms->{$dimm->{data}->{id}}->{addr} = $dimm->{data}->{addr}; -- 2.30.2 ___ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v4 qemu-server 07/16] memory: use static_memory in foreach_dimm
Signed-off-by: Alexandre Derumier --- PVE/QemuServer/Memory.pm | 12 +--- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/PVE/QemuServer/Memory.pm b/PVE/QemuServer/Memory.pm index 5dc2cb8..32fbdc5 100644 --- a/PVE/QemuServer/Memory.pm +++ b/PVE/QemuServer/Memory.pm @@ -151,17 +151,15 @@ sub get_numa_guest_to_host_map { } sub foreach_dimm{ -my ($conf, $vmid, $memory, $sockets, $func) = @_; +my ($conf, $vmid, $memory, $static_memory, $func) = @_; my $dimm_id = 0; -my $current_size = 0; +my $current_size = $static_memory; my $dimm_size = 0; if($conf->{hugepages} && $conf->{hugepages} == 1024) { - $current_size = 1024 * $sockets; $dimm_size = 1024; } else { - $current_size = 1024; $dimm_size = 512; } @@ -238,7 +236,7 @@ sub qemu_memory_hotplug { my $numa_hostmap; - foreach_dimm($conf, $vmid, $value, $sockets, sub { + foreach_dimm($conf, $vmid, $value, $static_memory, sub { my ($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory) = @_; return if $current_size <= get_current_memory($conf->{memory}); @@ -420,7 +418,7 @@ sub config { } if ($hotplug) { - foreach_dimm($conf, $vmid, $memory, $sockets, sub { + foreach_dimm($conf, $vmid, $memory, $static_memory, sub { my ($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory) = @_; my $mem_object = print_mem_object($conf, "mem-$name", $dimm_size); @@ -585,7 +583,7 @@ sub hugepages_topology { if ($hotplug) { my $numa_hostmap = get_numa_guest_to_host_map($conf); - foreach_dimm($conf, undef, $memory, $sockets, sub { + foreach_dimm($conf, undef, $memory, $static_memory, sub { my ($conf, undef, $name, $dimm_size, $numanode, $current_size, $memory) = @_; $numanode = $numa_hostmap->{$numanode}; -- 2.30.2 ___ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v4 qemu-server 12/16] memory: use 64 slots && static dimm size when max is defined
default kernel vhost config only support 64 slots by default, for performance since 2015. Original memory hotplug code was done before, using qemu max supported 255 slots. To reach max mem (4TB), we used incremental dimm size. Instead of dynamic memory size, use 1 static dimm size, compute from max memory/64. We also force a static memory to 4GB, as memory under 4G don't works fine with unplug Fix: https://bugzilla.proxmox.com/show_bug.cgi?id=3446 https://bugzilla.proxmox.com/show_bug.cgi?id=1426 Signed-off-by: Alexandre Derumier --- PVE/QemuServer/Memory.pm | 20 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/PVE/QemuServer/Memory.pm b/PVE/QemuServer/Memory.pm index cf1ddb9..1b1c99d 100644 --- a/PVE/QemuServer/Memory.pm +++ b/PVE/QemuServer/Memory.pm @@ -19,6 +19,7 @@ get_host_max_mem ); my $MAX_NUMA = 8; +my $MAX_SLOTS = 64; our $memory_fmt = { current => { @@ -71,7 +72,13 @@ my sub get_static_mem { my $static_memory = 0; my $memory = parse_memory($conf->{memory}); -if ($hotplug) { +if ($memory->{max}) { + my $dimm_size = $memory->{max} / $MAX_SLOTS; + #static mem can't be lower than 4G and lower than 1 dimmsize by socket + $static_memory = $dimm_size * $sockets; + $static_memory = 4096 if $static_memory < 4096; +} elsif ($hotplug) { + #legacy $static_memory = 1024; $static_memory = $static_memory * $sockets if ($conf->{hugepages} && $conf->{hugepages} == 1024); } else { @@ -194,7 +201,10 @@ sub foreach_dimm{ my $current_size = $static_memory; my $dimm_size = 0; -if($conf->{hugepages} && $conf->{hugepages} == 1024) { +my $confmem = parse_memory($conf->{memory}); +if ($confmem->{max}) { + $dimm_size = $confmem->{max} / $MAX_SLOTS; +} elsif($conf->{hugepages} && $conf->{hugepages} == 1024) { $dimm_size = 1024; } else { $dimm_size = 512; @@ -213,7 +223,7 @@ sub foreach_dimm{ &$func($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory); return $current_size if $current_size >= $memory; } - $dimm_size *= 2; + $dimm_size *= 2 if !$confmem->{max}; } } @@ -368,7 +378,9 @@ sub config { } die "minimum memory must be ${static_memory}MB\n" if($memory < $static_memory); - push @$cmd, '-m', "size=${static_memory},slots=255,maxmem=${MAX_MEM}M"; + my $confmem = parse_memory($conf->{memory}); + my $slots = $confmem->{max} ? $MAX_SLOTS : 255; + push @$cmd, '-m', "size=${static_memory},slots=$slots,maxmem=${MAX_MEM}M"; } else { -- 2.30.2 ___ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH v4 qemu-server 09/16] memory: get_max_mem: use config memory max
verify than defined vm memorymax is not bigger than host cpu supported memory Add add early check in update vm api Signed-off-by: Alexandre Derumier --- PVE/API2/Qemu.pm | 32 ++-- PVE/QemuServer/Memory.pm | 19 ++- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm index 9b80da1..6627910 100644 --- a/PVE/API2/Qemu.pm +++ b/PVE/API2/Qemu.pm @@ -32,7 +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::Memory qw(get_current_memory parse_memory get_host_max_mem); use PVE::QemuMigrate; use PVE::RPCEnvironment; use PVE::AccessControl; @@ -476,6 +476,26 @@ my $create_disks = sub { return ($vollist, $res); }; +my $check_memory_param = sub { +my ($conf, $param) = @_; + +my $mem = parse_memory($param->{memory}); +my $host_max_mem = get_host_max_mem($conf); + +die "memory max can't be bigger than supported cpu architecture $host_max_mem MiB\n" + if $mem->{max} && $mem->{max} > $host_max_mem; + +if ($param->{memory} || defined($param->{balloon})) { + + 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" + if $balloon && $balloon > $maxmem; +} +}; + my $check_cpu_model_access = sub { my ($rpcenv, $authuser, $new, $existing) = @_; @@ -1606,15 +1626,7 @@ my $update_vm_api = sub { } } - if ($param->{memory} || defined($param->{balloon})) { - - 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" - if $balloon && $balloon > $maxmem; - } + &$check_memory_param($conf, $param); PVE::Cluster::log_msg('info', $authuser, "update VM $vmid: " . join (' ', @paramarr)); diff --git a/PVE/QemuServer/Memory.pm b/PVE/QemuServer/Memory.pm index deeb88f..c912e4f 100644 --- a/PVE/QemuServer/Memory.pm +++ b/PVE/QemuServer/Memory.pm @@ -14,6 +14,8 @@ use base qw(Exporter); our @EXPORT_OK = qw( get_current_memory +parse_memory +get_host_max_mem ); my $MAX_NUMA = 8; @@ -96,7 +98,7 @@ sub get_host_phys_address_bits { return; # undef, cannot really do anything.. } -my sub get_max_mem { +sub get_host_max_mem { my ($conf) = @_; my $cpu = {}; @@ -130,6 +132,21 @@ my sub get_max_mem { return $bits_to_max_mem > 4*1024*1024 ? 4*1024*1024 : $bits_to_max_mem; } +my sub get_max_mem { +my ($conf) = @_; + +my $host_max_mem = get_host_max_mem($conf); +my $mem = parse_memory($conf->{memory}); + +if ($mem->{max}) { + die "configured memory max can't be bigger than supported cpu architecture $host_max_mem MiB\n" + if $mem->{max} > $host_max_mem; + return $mem->{max}; +} + +return $host_max_mem; +} + sub get_current_memory { my ($value) = @_; -- 2.30.2 ___ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH manager 2/2] lxc: Add `Disconnect` option for network interfaces
Signed-off-by: Christoph Heiss --- www/manager6/Parser.js | 3 +++ www/manager6/lxc/Network.js | 13 + 2 files changed, 16 insertions(+) diff --git a/www/manager6/Parser.js b/www/manager6/Parser.js index 9f7b2c84..c3772d3b 100644 --- a/www/manager6/Parser.js +++ b/www/manager6/Parser.js @@ -298,6 +298,8 @@ Ext.define('PVE.Parser', { data[match_res[1]] = match_res[2]; } else if ((match_res = p.match(/^firewall=(\d+)$/)) !== null) { data.firewall = PVE.Parser.parseBoolean(match_res[1]); + } else if ((match_res = p.match(/^link_down=(\d+)$/)) !== null) { + data.link_down = PVE.Parser.parseBoolean(match_res[1]); } else if (!p.match(/^type=\S+$/)) { console.warn(`could not parse LXC network string ${p}`); } @@ -319,6 +321,7 @@ Ext.define('PVE.Parser', { name: 1, rate: 1, tag: 1, + link_down: 1, }; return Object.entries(config) .filter(([k, v]) => v !== undefined && v !== '' && knownKeys[k]) diff --git a/www/manager6/lxc/Network.js b/www/manager6/lxc/Network.js index 85033bd8..746924b3 100644 --- a/www/manager6/lxc/Network.js +++ b/www/manager6/lxc/Network.js @@ -282,6 +282,12 @@ Ext.define('PVE.lxc.NetworkInputPanel', { minValue: 576, maxValue: 65535, }, + { + xtype: 'proxmoxcheckbox', + fieldLabel: gettext('Disconnect'), + name: 'link_down', + value: cdata.link_down, + }, ]; me.advancedColumn2 = [ @@ -539,6 +545,12 @@ Ext.define('PVE.lxc.NetworkView', { width: 80, dataIndex: 'mtu', }, + { + header: gettext('Disconnected'), + width: 100, + dataIndex: 'link_down', + renderer: Proxmox.Utils.format_boolean, + }, ], listeners: { activate: me.load, @@ -564,6 +576,7 @@ Ext.define('PVE.lxc.NetworkView', { 'tag', 'firewall', 'mtu', + 'link_down', ], }); }); -- 2.39.1 ___ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH container 1/2] net: Add `link_down` config to allow setting interfaces as disconnected
If this network option is set, the host-side link will be forced down. This has the effect that the interface inside the container has LOWERLAYERDOWN set, which basically means that the PHY is considered down, thus effectivly being "unplugged". Also fix some trailing whitespace while touching the file. Signed-off-by: Christoph Heiss --- src/PVE/LXC.pm| 20 +--- src/PVE/LXC/Config.pm | 5 + src/lxcnetaddbr | 3 ++- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/PVE/LXC.pm b/src/PVE/LXC.pm index ce6d5a5..039a476 100644 --- a/src/PVE/LXC.pm +++ b/src/PVE/LXC.pm @@ -668,7 +668,7 @@ sub update_lxc_config { # some init scripts expect a linux terminal (turnkey). $raw .= "lxc.environment = TERM=linux\n"; - + my $utsname = $conf->{hostname} || "CT$vmid"; $raw .= "lxc.uts.name = $utsname\n"; @@ -932,8 +932,9 @@ sub update_net { my $oldnet = PVE::LXC::Config->parse_lxc_network($oldnetcfg); if (safe_string_ne($oldnet->{hwaddr}, $newnet->{hwaddr}) || - safe_string_ne($oldnet->{name}, $newnet->{name})) { - + safe_string_ne($oldnet->{name}, $newnet->{name}) || + defined($oldnet->{link_down}) != defined($newnet->{link_down}) + ) { PVE::Network::veth_delete($veth); delete $conf->{$opt}; PVE::LXC::Config->write_config($vmid, $conf); @@ -1010,6 +1011,11 @@ sub hotplug_net { $cmd = ['lxc-attach', '-n', $vmid, '-s', 'NETWORK', '--', '/sbin/ip', 'link', 'set', $eth ,'up' ]; PVE::Tools::run_command($cmd); +# In case the network device should be disconnected, force the host-link down +if (defined($newnet->{link_down})) { + PVE::Tools::run_command(['/sbin/ip', 'link', 'set', 'dev', $veth, 'down']); +} + my $done = { type => 'veth' }; foreach (qw(bridge tag firewall hwaddr name)) { $done->{$_} = $newnet->{$_} if $newnet->{$_}; @@ -1703,14 +1709,14 @@ sub __mountpoint_mount { my $type = $mountpoint->{type}; my $quota = !$snapname && !$mountpoint->{ro} && $mountpoint->{quota}; my $mounted_dev; - + return if !$volid || !$mount; $mount =~ s!/+!/!g; my $mount_path; my ($mpfd, $parentfd, $last_dir); - + if (defined($rootdir)) { ($rootdir, $mount_path, $mpfd, $parentfd, $last_dir) = __mount_prepare_rootdir($rootdir, $mount, $rootuid, $rootgid); @@ -1719,7 +1725,7 @@ sub __mountpoint_mount { if (defined($stage_mount)) { $mount_path = $rootdir; } - + my ($storage, $volname) = PVE::Storage::parse_volume_id($volid, 1); die "unknown snapshot path for '$volid'" if !$storage && defined($snapname); @@ -1828,7 +1834,7 @@ sub __mountpoint_mount { warn "cannot enable quota control for bind mounts\n" if $quota; return wantarray ? ($volid, 0, undef) : $volid; } - + die "unsupported storage"; } diff --git a/src/PVE/LXC/Config.pm b/src/PVE/LXC/Config.pm index af25a96..1d4362e 100644 --- a/src/PVE/LXC/Config.pm +++ b/src/PVE/LXC/Config.pm @@ -814,6 +814,11 @@ our $netconf_desc = { description => "Apply rate limiting to the interface", optional => 1, }, +link_down => { + type => 'boolean', + description => 'Whether this interface should be disconnected (like pulling the plug).', + optional => 1, +}, }; PVE::JSONSchema::register_format('pve-lxc-network', $netconf_desc); diff --git a/src/lxcnetaddbr b/src/lxcnetaddbr index 83052e1..d8c6767 100755 --- a/src/lxcnetaddbr +++ b/src/lxcnetaddbr @@ -58,7 +58,8 @@ if (-d "/sys/class/net/$iface") { #avoid insecure dependency; ($bridgemtu) = $bridgemtu =~ /(\d+)/; -PVE::Tools::run_command("/sbin/ip link set dev $iface up mtu $bridgemtu"); +my $linkstate = defined($net->{link_down}) ? 'down' : 'up'; +PVE::Tools::run_command("/sbin/ip link set dev $iface $linkstate mtu $bridgemtu"); PVE::Tools::run_command("/sbin/ip addr add 0.0.0.0/0 dev $iface"); if ($have_sdn) { -- 2.39.1 ___ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
[pve-devel] [PATCH container/manager 0/2] fix #3413: Add `Disconnect` option for LXC networks
This adds a `Disconnect` option for network interfaces on LXC containers, much like it already exists for VMs. This has been requested in #3413 [0] and seems useful, esp. considering we already support the same thing for VMs. One thing to note is that LXC does not seem to support the notion of setting an interface down. The `flags` property would suggest that this possible [1], but AFAICS it does not work. I tried setting the value as empty and to something else than "up" (since that is really the only supported option [2][3]), which both had absolutely no effect. The solution was to force the host-side link of the container network down, thus effectively becoming "physically" disconnected. [0] https://bugzilla.proxmox.com/show_bug.cgi?id=3413 [1] https://linuxcontainers.org/lxc/manpages/man5/lxc.container.conf.5.html#lbAO [2] https://github.com/lxc/lxc/blob/08f0e769/src/lxc/confile.c#L453-L467 [3] https://github.com/lxc/lxc/blob/08f0e769/src/lxc/confile.c#L5933-L5952 pve-container: Christoph Heiss (1): net: Add `link_down` config to allow setting interfaces as disconnected src/PVE/LXC.pm| 20 +--- src/PVE/LXC/Config.pm | 5 + src/lxcnetaddbr | 3 ++- 3 files changed, 20 insertions(+), 8 deletions(-) pve-manager: Christoph Heiss (1): lxc: Add `Disconnect` option for network interfaces www/manager6/Parser.js | 3 +++ www/manager6/lxc/Network.js | 13 + 2 files changed, 16 insertions(+) -- 2.39.1 ___ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
Re: [pve-devel] [PATCH container 1/2] net: Add `link_down` config to allow setting interfaces as disconnected
On Mon, Feb 13, 2023 at 02:56:59PM +0100, Christoph Heiss wrote: > If this network option is set, the host-side link will be forced down. > This has the effect that the interface inside the container has > LOWERLAYERDOWN set, which basically means that the PHY is considered > down, thus effectivly being "unplugged". > > Also fix some trailing whitespace while touching the file. > > Signed-off-by: Christoph Heiss > --- > src/PVE/LXC.pm| 20 +--- > src/PVE/LXC/Config.pm | 5 + > src/lxcnetaddbr | 3 ++- > 3 files changed, 20 insertions(+), 8 deletions(-) > > diff --git a/src/PVE/LXC.pm b/src/PVE/LXC.pm > index ce6d5a5..039a476 100644 > --- a/src/PVE/LXC.pm > +++ b/src/PVE/LXC.pm > @@ -668,7 +668,7 @@ sub update_lxc_config { > > # some init scripts expect a linux terminal (turnkey). > $raw .= "lxc.environment = TERM=linux\n"; > - > + > my $utsname = $conf->{hostname} || "CT$vmid"; > $raw .= "lxc.uts.name = $utsname\n"; > > @@ -932,8 +932,9 @@ sub update_net { > my $oldnet = PVE::LXC::Config->parse_lxc_network($oldnetcfg); > > if (safe_string_ne($oldnet->{hwaddr}, $newnet->{hwaddr}) || > - safe_string_ne($oldnet->{name}, $newnet->{name})) { > - > + safe_string_ne($oldnet->{name}, $newnet->{name}) || > + defined($oldnet->{link_down}) != defined($newnet->{link_down}) Doing this here would cause the interface to be deleted and recreated in a "down" state, which is much more disruptive than it needs to be. Instead, this should be treated more like we do changing the 'bridge' property (the 'else' case just below this), and stop after the `tap_unplug` for the 'down' case. > + ) { > PVE::Network::veth_delete($veth); > delete $conf->{$opt}; > PVE::LXC::Config->write_config($vmid, $conf); > @@ -1010,6 +1011,11 @@ sub hotplug_net { > $cmd = ['lxc-attach', '-n', $vmid, '-s', 'NETWORK', '--', '/sbin/ip', > 'link', 'set', $eth ,'up' ]; > PVE::Tools::run_command($cmd); > > +# In case the network device should be disconnected, force the host-link > down > +if (defined($newnet->{link_down})) { > + PVE::Tools::run_command(['/sbin/ip', 'link', 'set', 'dev', $veth, > 'down']); These interfaces are usually part of a bridge, and therefore the next `ifreload` (and probably some other things) would re-enable them automatically. We do need to actually "unplug" them from the bridge (tap_unplug) to avoid this. > +} > + > my $done = { type => 'veth' }; > foreach (qw(bridge tag firewall hwaddr name)) { > $done->{$_} = $newnet->{$_} if $newnet->{$_}; > @@ -1703,14 +1709,14 @@ sub __mountpoint_mount { > my $type = $mountpoint->{type}; > my $quota = !$snapname && !$mountpoint->{ro} && $mountpoint->{quota}; > my $mounted_dev; > - > + > return if !$volid || !$mount; > > $mount =~ s!/+!/!g; > > my $mount_path; > my ($mpfd, $parentfd, $last_dir); > - > + > if (defined($rootdir)) { > ($rootdir, $mount_path, $mpfd, $parentfd, $last_dir) = > __mount_prepare_rootdir($rootdir, $mount, $rootuid, $rootgid); > @@ -1719,7 +1725,7 @@ sub __mountpoint_mount { > if (defined($stage_mount)) { > $mount_path = $rootdir; > } > - > + > my ($storage, $volname) = PVE::Storage::parse_volume_id($volid, 1); > > die "unknown snapshot path for '$volid'" if !$storage && > defined($snapname); > @@ -1828,7 +1834,7 @@ sub __mountpoint_mount { > warn "cannot enable quota control for bind mounts\n" if $quota; > return wantarray ? ($volid, 0, undef) : $volid; > } > - > + > die "unsupported storage"; > } > > diff --git a/src/PVE/LXC/Config.pm b/src/PVE/LXC/Config.pm > index af25a96..1d4362e 100644 > --- a/src/PVE/LXC/Config.pm > +++ b/src/PVE/LXC/Config.pm > @@ -814,6 +814,11 @@ our $netconf_desc = { > description => "Apply rate limiting to the interface", > optional => 1, > }, > +link_down => { > + type => 'boolean', > + description => 'Whether this interface should be disconnected (like > pulling the plug).', > + optional => 1, > +}, > }; > PVE::JSONSchema::register_format('pve-lxc-network', $netconf_desc); > > diff --git a/src/lxcnetaddbr b/src/lxcnetaddbr > index 83052e1..d8c6767 100755 > --- a/src/lxcnetaddbr > +++ b/src/lxcnetaddbr > @@ -58,7 +58,8 @@ if (-d "/sys/class/net/$iface") { > #avoid insecure dependency; > ($bridgemtu) = $bridgemtu =~ /(\d+)/; > > -PVE::Tools::run_command("/sbin/ip link set dev $iface up mtu > $bridgemtu"); > +my $linkstate = defined($net->{link_down}) ? 'down' : 'up'; We need to skip the rest altogether if the link is supposed to stay down reliably. As mentioned above, a 'down' interface that is still plugged into a bridge will get activated sooner or later... > +PVE::Tools::run_command("/sbin/ip link set dev $iface $linkstate mtu > $bridgemtu"); > PVE::Tools::run_command("/sbin/ip