]> git.proxmox.com Git - qemu-server.git/blob - PVE/QemuServer/Memory.pm
move qemu_memory_hotplug && qemu_dimm_list to QemuServer::Memory
[qemu-server.git] / PVE / QemuServer / Memory.pm
1 package PVE::QemuServer::Memory;
2
3 use strict;
4 use warnings;
5 use PVE::QemuServer;
6
7 my $MAX_MEM = 4194304;
8 my $STATICMEM = 1024;
9
10 sub foreach_dimm{
11 my ($conf, $vmid, $memory, $sockets, $func) = @_;
12
13 my $dimm_id = 0;
14 my $current_size = 1024;
15 my $dimm_size = 512;
16 return if $current_size == $memory;
17
18 for (my $j = 0; $j < 8; $j++) {
19 for (my $i = 0; $i < 32; $i++) {
20 my $name = "dimm${dimm_id}";
21 $dimm_id++;
22 my $numanode = $i % $sockets;
23 $current_size += $dimm_size;
24 &$func($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory);
25 return $current_size if $current_size >= $memory;
26 }
27 $dimm_size *= 2;
28 }
29 }
30
31 sub foreach_reverse_dimm {
32 my ($conf, $vmid, $memory, $sockets, $func) = @_;
33
34 my $dimm_id = 253;
35 my $current_size = 4177920;
36 my $dimm_size = 65536;
37 return if $current_size == $memory;
38
39 for (my $j = 0; $j < 8; $j++) {
40 for (my $i = 0; $i < 32; $i++) {
41 my $name = "dimm${dimm_id}";
42 $dimm_id--;
43 my $numanode = $i % $sockets;
44 $current_size -= $dimm_size;
45 &$func($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory);
46 return $current_size if $current_size <= $memory;
47 }
48 $dimm_size /= 2;
49 }
50 }
51
52 sub qemu_memory_hotplug {
53 my ($vmid, $conf, $defaults, $opt, $value) = @_;
54
55 return $value if !check_running($vmid);
56
57 my $memory = $conf->{memory} || $defaults->{memory};
58 $value = $defaults->{memory} if !$value;
59 return $value if $value == $memory;
60
61 my $static_memory = $STATICMEM;
62 my $dimm_memory = $memory - $static_memory;
63
64 die "memory can't be lower than $static_memory MB" if $value < $static_memory;
65 die "you cannot add more memory than $MAX_MEM MB!\n" if $memory > $MAX_MEM;
66
67
68 my $sockets = 1;
69 $sockets = $conf->{sockets} if $conf->{sockets};
70
71 if($value > $memory) {
72
73 foreach_dimm($conf, $vmid, $value, $sockets, sub {
74 my ($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory) = @_;
75
76 return if $current_size <= $conf->{memory};
77
78 eval { PVE::QemuServer::vm_mon_cmd($vmid, "object-add", 'qom-type' => "memory-backend-ram", id => "mem-$name", props => { size => int($dimm_size*1024*1024) } ) };
79 if (my $err = $@) {
80 eval { PVE::QemuServer::qemu_objectdel($vmid, "mem-$name"); };
81 die $err;
82 }
83
84 eval { PVE::QemuServer::vm_mon_cmd($vmid, "device_add", driver => "pc-dimm", id => "$name", memdev => "mem-$name", node => $numanode) };
85 if (my $err = $@) {
86 eval { PVE::QemuServer::qemu_objectdel($vmid, "mem-$name"); };
87 die $err;
88 }
89 #update conf after each succesful module hotplug
90 $conf->{memory} = $current_size;
91 PVE::QemuConfig->write_config($vmid, $conf);
92 });
93
94 } else {
95
96 foreach_reverse_dimm($conf, $vmid, $value, $sockets, sub {
97 my ($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory) = @_;
98
99 return if $current_size >= $conf->{memory};
100 print "try to unplug memory dimm $name\n";
101
102 my $retry = 0;
103 while (1) {
104 eval { PVE::QemuServer::qemu_devicedel($vmid, $name) };
105 sleep 3;
106 my $dimm_list = qemu_dimm_list($vmid);
107 last if !$dimm_list->{$name};
108 raise_param_exc({ $name => "error unplug memory module" }) if $retry > 5;
109 $retry++;
110 }
111
112 #update conf after each succesful module unplug
113 $conf->{memory} = $current_size;
114
115 eval { PVE::QemuServer::qemu_objectdel($vmid, "mem-$name"); };
116 PVE::QemuConfig->write_config($vmid, $conf);
117 });
118 }
119 }
120
121 sub qemu_dimm_list {
122 my ($vmid) = @_;
123
124 my $dimmarray = PVE::QemuServer::vm_mon_cmd_nocheck($vmid, "query-memory-devices");
125 my $dimms = {};
126
127 foreach my $dimm (@$dimmarray) {
128
129 $dimms->{$dimm->{data}->{id}}->{id} = $dimm->{data}->{id};
130 $dimms->{$dimm->{data}->{id}}->{node} = $dimm->{data}->{node};
131 $dimms->{$dimm->{data}->{id}}->{addr} = $dimm->{data}->{addr};
132 $dimms->{$dimm->{data}->{id}}->{size} = $dimm->{data}->{size};
133 $dimms->{$dimm->{data}->{id}}->{slot} = $dimm->{data}->{slot};
134 }
135 return $dimms;
136 }
137
138 1;
139