]>
git.proxmox.com Git - qemu-server.git/blob - PVE/QemuServer/Memory.pm
3c9659c6d0f78c6452c2db7ff9faff0cc15b40fb
1 package PVE
::QemuServer
::Memory
;
12 my ($conf, $vmid, $memory, $sockets, $func) = @_;
15 my $current_size = 1024;
17 return if $current_size == $memory;
19 for (my $j = 0; $j < 8; $j++) {
20 for (my $i = 0; $i < 32; $i++) {
21 my $name = "dimm${dimm_id}";
23 my $numanode = $i % $sockets;
24 $current_size += $dimm_size;
25 &$func($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory);
26 return $current_size if $current_size >= $memory;
32 sub foreach_reverse_dimm
{
33 my ($conf, $vmid, $memory, $sockets, $func) = @_;
36 my $current_size = 4177920;
37 my $dimm_size = 65536;
38 return if $current_size == $memory;
40 for (my $j = 0; $j < 8; $j++) {
41 for (my $i = 0; $i < 32; $i++) {
42 my $name = "dimm${dimm_id}";
44 my $numanode = $i % $sockets;
45 $current_size -= $dimm_size;
46 &$func($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory);
47 return $current_size if $current_size <= $memory;
53 sub qemu_memory_hotplug
{
54 my ($vmid, $conf, $defaults, $opt, $value) = @_;
56 return $value if !check_running
($vmid);
58 my $memory = $conf->{memory
} || $defaults->{memory
};
59 $value = $defaults->{memory
} if !$value;
60 return $value if $value == $memory;
62 my $static_memory = $STATICMEM;
63 my $dimm_memory = $memory - $static_memory;
65 die "memory can't be lower than $static_memory MB" if $value < $static_memory;
66 die "you cannot add more memory than $MAX_MEM MB!\n" if $memory > $MAX_MEM;
70 $sockets = $conf->{sockets
} if $conf->{sockets
};
72 if($value > $memory) {
74 foreach_dimm
($conf, $vmid, $value, $sockets, sub {
75 my ($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory) = @_;
77 return if $current_size <= $conf->{memory
};
79 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "object-add", 'qom-type' => "memory-backend-ram", id
=> "mem-$name", props
=> { size
=> int($dimm_size*1024*1024) } ) };
81 eval { PVE
::QemuServer
::qemu_objectdel
($vmid, "mem-$name"); };
85 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "device_add", driver
=> "pc-dimm", id
=> "$name", memdev
=> "mem-$name", node
=> $numanode) };
87 eval { PVE
::QemuServer
::qemu_objectdel
($vmid, "mem-$name"); };
90 #update conf after each succesful module hotplug
91 $conf->{memory
} = $current_size;
92 PVE
::QemuConfig-
>write_config($vmid, $conf);
97 foreach_reverse_dimm
($conf, $vmid, $value, $sockets, sub {
98 my ($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory) = @_;
100 return if $current_size >= $conf->{memory
};
101 print "try to unplug memory dimm $name\n";
105 eval { PVE
::QemuServer
::qemu_devicedel
($vmid, $name) };
107 my $dimm_list = qemu_dimm_list
($vmid);
108 last if !$dimm_list->{$name};
109 raise_param_exc
({ $name => "error unplug memory module" }) if $retry > 5;
113 #update conf after each succesful module unplug
114 $conf->{memory
} = $current_size;
116 eval { PVE
::QemuServer
::qemu_objectdel
($vmid, "mem-$name"); };
117 PVE
::QemuConfig-
>write_config($vmid, $conf);
125 my $dimmarray = PVE
::QemuServer
::vm_mon_cmd_nocheck
($vmid, "query-memory-devices");
128 foreach my $dimm (@$dimmarray) {
130 $dimms->{$dimm->{data
}->{id
}}->{id
} = $dimm->{data
}->{id
};
131 $dimms->{$dimm->{data
}->{id
}}->{node
} = $dimm->{data
}->{node
};
132 $dimms->{$dimm->{data
}->{id
}}->{addr
} = $dimm->{data
}->{addr
};
133 $dimms->{$dimm->{data
}->{id
}}->{size
} = $dimm->{data
}->{size
};
134 $dimms->{$dimm->{data
}->{id
}}->{slot
} = $dimm->{data
}->{slot
};
140 my ($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd) = @_;
142 my $memory = $conf->{memory
} || $defaults->{memory
};
143 my $static_memory = 0;
146 if ($hotplug_features->{memory
}) {
147 die "NUMA need to be enabled for memory hotplug\n" if !$conf->{numa
};
148 die "Total memory is bigger than ${MAX_MEM}MB\n" if $memory > $MAX_MEM;
149 $static_memory = $STATICMEM;
150 die "minimum memory must be ${static_memory}MB\n" if($memory < $static_memory);
151 $dimm_memory = $memory - $static_memory;
152 push @$cmd, '-m', "size=${static_memory},slots=255,maxmem=${MAX_MEM}M";
156 $static_memory = $memory;
157 push @$cmd, '-m', $static_memory;
162 my $numa_totalmemory = undef;
163 for (my $i = 0; $i < $MAX_NUMA; $i++) {
164 next if !$conf->{"numa$i"};
165 my $numa = PVE
::QemuServer
::parse_numa
($conf->{"numa$i"});
168 die "missing NUMA node$i memory value\n" if !$numa->{memory
};
169 my $numa_memory = $numa->{memory
};
170 $numa_totalmemory += $numa_memory;
171 my $numa_object = "memory-backend-ram,id=ram-node$i,size=${numa_memory}M";
174 my $cpulists = $numa->{cpus
};
175 die "missing NUMA node$i cpus\n" if !defined($cpulists);
176 my $cpus = join(',', map {
177 my ($start, $end) = @$_;
178 defined($end) ?
"$start-$end" : $start
182 my $hostnodelists = $numa->{hostnodes
};
183 if (defined($hostnodelists)) {
185 foreach my $hostnoderange (@$hostnodelists) {
186 my ($start, $end) = @$hostnoderange;
187 $hostnodes .= ',' if $hostnodes;
188 $hostnodes .= $start;
189 $hostnodes .= "-$end" if defined($end);
191 for (my $i = $start; $i <= $end; ++$i ) {
192 die "host NUMA node$i don't exist\n" if ! -d
"/sys/devices/system/node/node$i/";
197 my $policy = $numa->{policy
};
198 die "you need to define a policy for hostnode $hostnodes\n" if !$policy;
199 $numa_object .= ",host-nodes=$hostnodes,policy=$policy";
202 push @$cmd, '-object', $numa_object;
203 push @$cmd, '-numa', "node,nodeid=$i,cpus=$cpus,memdev=ram-node$i";
206 die "total memory for NUMA nodes must be equal to vm static memory\n"
207 if $numa_totalmemory && $numa_totalmemory != $static_memory;
209 #if no custom tology, we split memory and cores across numa nodes
210 if(!$numa_totalmemory) {
212 my $numa_memory = ($static_memory / $sockets) . "M";
214 for (my $i = 0; $i < $sockets; $i++) {
216 my $cpustart = ($cores * $i);
217 my $cpuend = ($cpustart + $cores - 1) if $cores && $cores > 1;
218 my $cpus = $cpustart;
219 $cpus .= "-$cpuend" if $cpuend;
221 push @$cmd, '-object', "memory-backend-ram,size=$numa_memory,id=ram-node$i";
222 push @$cmd, '-numa', "node,nodeid=$i,cpus=$cpus,memdev=ram-node$i";
227 if ($hotplug_features->{memory
}) {
228 foreach_dimm
($conf, $vmid, $memory, $sockets, sub {
229 my ($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory) = @_;
230 push @$cmd, "-object" , "memory-backend-ram,id=mem-$name,size=${dimm_size}M";
231 push @$cmd, "-device", "pc-dimm,id=$name,memdev=mem-$name,node=$numanode";
233 #if dimm_memory is not aligned to dimm map
234 if($current_size > $memory) {
235 $conf->{memory
} = $current_size;
236 PVE
::QemuConfig-
>write_config($vmid, $conf);