1 package PVE
::QemuServer
;
22 use Storable
qw(dclone);
23 use PVE
::Exception
qw(raise raise_param_exc);
25 use PVE
::Tools
qw(run_command lock_file lock_file_full file_read_firstline dir_glob_foreach $IPV6RE);
26 use PVE
::JSONSchema
qw(get_standard_option);
27 use PVE
::Cluster
qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file);
32 use PVE
::RPCEnvironment
;
33 use PVE
::QemuServer
::PCI
qw(print_pci_addr print_pcie_addr);
34 use PVE
::QemuServer
::Memory
;
35 use PVE
::QemuServer
::USB
qw(parse_usb_device);
36 use PVE
::QemuServer
::Cloudinit
;
37 use Time
::HiRes
qw(gettimeofday);
38 use File
::Copy
qw(copy);
41 my $OVMF_CODE = '/usr/share/kvm/OVMF_CODE-pure-efi.fd';
42 my $OVMF_VARS = '/usr/share/kvm/OVMF_VARS-pure-efi.fd';
44 my $qemu_snap_storage = {rbd
=> 1, sheepdog
=> 1};
46 my $cpuinfo = PVE
::ProcFSTools
::read_cpuinfo
();
48 my $QEMU_FORMAT_RE = qr/raw|cow|qcow|qcow2|qed|vmdk|cloop/;
50 # Note about locking: we use flock on the config file protect
51 # against concurent actions.
52 # Aditionaly, we have a 'lock' setting in the config file. This
53 # can be set to 'migrate', 'backup', 'snapshot' or 'rollback'. Most actions are not
54 # allowed when such lock is set. But you can ignore this kind of
55 # lock with the --skiplock flag.
57 cfs_register_file
('/qemu-server/',
61 PVE
::JSONSchema
::register_standard_option
('pve-qm-stateuri', {
62 description
=> "Some command save/restore state from this location.",
68 PVE
::JSONSchema
::register_standard_option
('pve-snapshot-name', {
69 description
=> "The name of the snapshot.",
70 type
=> 'string', format
=> 'pve-configid',
74 PVE
::JSONSchema
::register_standard_option
('pve-qm-image-format', {
76 enum
=> [qw(raw cow qcow qed qcow2 vmdk cloop)],
77 description
=> "The drive's backing file's data format.",
81 #no warnings 'redefine';
84 my ($controller, $vmid, $option, $value) = @_;
86 my $path = "/sys/fs/cgroup/$controller/qemu.slice/$vmid.scope/$option";
87 PVE
::ProcFSTools
::write_proc_entry
($path, $value);
91 my $nodename = PVE
::INotify
::nodename
();
93 mkdir "/etc/pve/nodes/$nodename";
94 my $confdir = "/etc/pve/nodes/$nodename/qemu-server";
97 my $var_run_tmpdir = "/var/run/qemu-server";
98 mkdir $var_run_tmpdir;
100 my $lock_dir = "/var/lock/qemu-server";
103 my $pcisysfs = "/sys/bus/pci";
105 my $cpu_vendor_list = {
107 486 => 'GenuineIntel',
108 pentium
=> 'GenuineIntel',
109 pentium2
=> 'GenuineIntel',
110 pentium3
=> 'GenuineIntel',
111 coreduo
=> 'GenuineIntel',
112 core2duo
=> 'GenuineIntel',
113 Conroe
=> 'GenuineIntel',
114 Penryn
=> 'GenuineIntel',
115 Nehalem
=> 'GenuineIntel',
116 'Nehalem-IBRS' => 'GenuineIntel',
117 Westmere
=> 'GenuineIntel',
118 'Westmere-IBRS' => 'GenuineIntel',
119 SandyBridge
=> 'GenuineIntel',
120 'SandyBridge-IBRS' => 'GenuineIntel',
121 IvyBridge
=> 'GenuineIntel',
122 'IvyBridge-IBRS' => 'GenuineIntel',
123 Haswell
=> 'GenuineIntel',
124 'Haswell-IBRS' => 'GenuineIntel',
125 'Haswell-noTSX' => 'GenuineIntel',
126 'Haswell-noTSX-IBRS' => 'GenuineIntel',
127 Broadwell
=> 'GenuineIntel',
128 'Broadwell-IBRS' => 'GenuineIntel',
129 'Broadwell-noTSX' => 'GenuineIntel',
130 'Broadwell-noTSX-IBRS' => 'GenuineIntel',
131 'Skylake-Client' => 'GenuineIntel',
132 'Skylake-Client-IBRS' => 'GenuineIntel',
133 'Skylake-Server' => 'GenuineIntel',
134 'Skylake-Server-IBRS' => 'GenuineIntel',
137 athlon
=> 'AuthenticAMD',
138 phenom
=> 'AuthenticAMD',
139 Opteron_G1
=> 'AuthenticAMD',
140 Opteron_G2
=> 'AuthenticAMD',
141 Opteron_G3
=> 'AuthenticAMD',
142 Opteron_G4
=> 'AuthenticAMD',
143 Opteron_G5
=> 'AuthenticAMD',
144 EPYC
=> 'AuthenticAMD',
145 'EPYC-IBPB' => 'AuthenticAMD',
147 # generic types, use vendor from host node
156 my $cpu_flag = qr/[+-](pcid|spec-ctrl)/;
160 description
=> "Emulated CPU type.",
162 enum
=> [ sort { "\L$a" cmp "\L$b" } keys %$cpu_vendor_list ],
167 description
=> "Do not identify as a KVM virtual machine.",
173 description
=> "List of additional CPU flags separated by ';'."
174 . " Use '+FLAG' to enable, '-FLAG' to disable a flag."
175 . " Currently supported flags: 'pcid', 'spec-ctrl'.",
176 format_description
=> '+FLAG[;-FLAG...]',
178 pattern
=> qr/$cpu_flag(;$cpu_flag)*/,
187 enum
=> [qw(i6300esb ib700)],
188 description
=> "Watchdog type to emulate.",
189 default => 'i6300esb',
194 enum
=> [qw(reset shutdown poweroff pause debug none)],
195 description
=> "The action to perform if after activation the guest fails to poll the watchdog in time.",
199 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', $watchdog_fmt);
205 description
=> "Specifies whether a VM will be started during system bootup.",
211 description
=> "Automatic restart after crash (currently ignored).",
216 type
=> 'string', format
=> 'pve-hotplug-features',
217 description
=> "Selectively enable hotplug features. This is a comma separated list of hotplug features: 'network', 'disk', 'cpu', 'memory' and 'usb'. Use '0' to disable hotplug completely. Value '1' is an alias for the default 'network,disk,usb'.",
218 default => 'network,disk,usb',
223 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
229 description
=> "Lock/unlock the VM.",
230 enum
=> [qw(migrate backup snapshot rollback)],
235 description
=> "Limit of CPU usage.",
236 verbose_description
=> "Limit of CPU usage.\n\nNOTE: If the computer has 2 CPUs, it has total of '2' CPU time. Value '0' indicates no CPU limit.",
244 description
=> "CPU weight for a VM.",
245 verbose_description
=> "CPU weight for a VM. Argument is used in the kernel fair scheduler. The larger the number is, the more CPU time this VM gets. Number is relative to weights of all the other running VMs.",
253 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
260 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
266 description
=> "Amount of memory shares for auto-ballooning. The larger the number is, the more memory this VM gets. Number is relative to weights of all other running VMs. Using zero disables auto-ballooning",
274 description
=> "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.conf' configuration file.".
275 "It should not be necessary to set it.",
276 enum
=> PVE
::Tools
::kvmkeymaplist
(),
281 type
=> 'string', format
=> 'dns-name',
282 description
=> "Set a name for the VM. Only used on the configuration web interface.",
287 description
=> "SCSI controller model",
288 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
294 description
=> "Description for the VM. Only used on the configuration web interface. This is saved as comment inside the configuration file.",
299 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 l24 l26 solaris)],
300 description
=> "Specify guest operating system.",
301 verbose_description
=> <<EODESC,
302 Specify guest operating system. This is used to enable special
303 optimization/features for specific operating systems:
306 other;; unspecified OS
307 wxp;; Microsoft Windows XP
308 w2k;; Microsoft Windows 2000
309 w2k3;; Microsoft Windows 2003
310 w2k8;; Microsoft Windows 2008
311 wvista;; Microsoft Windows Vista
312 win7;; Microsoft Windows 7
313 win8;; Microsoft Windows 8/2012/2012r2
314 win10;; Microsoft Windows 10/2016
315 l24;; Linux 2.4 Kernel
316 l26;; Linux 2.6/3.X Kernel
317 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
323 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
324 pattern
=> '[acdn]{1,4}',
329 type
=> 'string', format
=> 'pve-qm-bootdisk',
330 description
=> "Enable booting from specified disk.",
331 pattern
=> '(ide|sata|scsi|virtio)\d+',
336 description
=> "The number of CPUs. Please use option -sockets instead.",
343 description
=> "The number of CPU sockets.",
350 description
=> "The number of cores per socket.",
357 description
=> "Enable/disable NUMA.",
363 description
=> "Enable/disable hugepages memory.",
364 enum
=> [qw(any 2 1024)],
369 description
=> "Number of hotplugged vcpus.",
376 description
=> "Enable/disable ACPI.",
382 description
=> "Enable/disable Qemu GuestAgent.",
388 description
=> "Enable/disable KVM hardware virtualization.",
394 description
=> "Enable/disable time drift fix.",
400 description
=> "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
405 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
410 description
=> "Select the VGA type.",
411 verbose_description
=> "Select the VGA type. If you want to use high resolution" .
412 " modes (>= 1280x1024x16) then you should use the options " .
413 "'std' or 'vmware'. Default is 'std' for win8/win7/w2k8, and " .
414 "'cirrus' for other OS types. The 'qxl' option enables the SPICE " .
415 "display sever. For win* OS you can select how many independent " .
416 "displays you want, Linux guests can add displays them self. " .
417 "You can also run without any graphic card, using a serial device" .
419 enum
=> [qw(std cirrus vmware qxl serial0 serial1 serial2 serial3 qxl2 qxl3 qxl4)],
423 type
=> 'string', format
=> 'pve-qm-watchdog',
424 description
=> "Create a virtual hardware watchdog device.",
425 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled" .
426 " (by a guest action), the watchdog must be periodically polled " .
427 "by an agent inside the guest or else the watchdog will reset " .
428 "the guest (or execute the respective action specified)",
433 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
434 description
=> "Set the initial date of the real time clock. Valid format for date are: 'now' or '2006-06-17T16:01:21' or '2006-06-17'.",
435 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
438 startup
=> get_standard_option
('pve-startup-order'),
442 description
=> "Enable/disable Template.",
448 description
=> "Arbitrary arguments passed to kvm.",
449 verbose_description
=> <<EODESCR,
450 Arbitrary arguments passed to kvm, for example:
452 args: -no-reboot -no-hpet
454 NOTE: this option is for experts only.
461 description
=> "Enable/disable the USB tablet device.",
462 verbose_description
=> "Enable/disable the USB tablet device. This device is " .
463 "usually needed to allow absolute mouse positioning with VNC. " .
464 "Else the mouse runs out of sync with normal VNC clients. " .
465 "If you're running lots of console-only guests on one host, " .
466 "you may consider disabling this to save some context switches. " .
467 "This is turned off by default if you use spice (-vga=qxl).",
472 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
476 migrate_downtime
=> {
479 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
485 type
=> 'string', format
=> 'pve-qm-ide',
486 typetext
=> '<volume>',
487 description
=> "This is an alias for option -ide2",
491 description
=> "Emulated CPU type.",
495 parent
=> get_standard_option
('pve-snapshot-name', {
497 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
501 description
=> "Timestamp for snapshots.",
507 type
=> 'string', format
=> 'pve-volume-id',
508 description
=> "Reference to a volume which stores the VM state. This is used internally for snapshots.",
510 vmstatestorage
=> get_standard_option
('pve-storage-id', {
511 description
=> "Default storage for VM state volumes/files.",
515 description
=> "Specific the Qemu machine type.",
517 pattern
=> '(pc|pc(-i440fx)?-\d+\.\d+(\.pxe)?|q35|pc-q35-\d+\.\d+(\.pxe)?)',
522 description
=> "Specify SMBIOS type 1 fields.",
523 type
=> 'string', format
=> 'pve-qm-smbios1',
530 description
=> "Sets the protection flag of the VM. This will disable the remove VM and remove disk operations.",
536 enum
=> [ qw(seabios ovmf) ],
537 description
=> "Select BIOS implementation.",
538 default => 'seabios',
542 my $confdesc_cloudinit = {
546 description
=> 'Specifies the cloud-init configuration format. The default depends on the configured operating system type (`ostype`. We use the `nocloud` format for Linux, and `configdrive2` for windows.',
547 enum
=> ['configdrive2', 'nocloud'],
552 description
=> "cloud-init: User name to change ssh keys and password for instead of the image's configured default user.",
557 description
=> 'cloud-init: Password to assign the user. Using this is generally not recommended. Use ssh keys instead. Also note that older cloud-init versions do not support hashed passwords.',
562 description
=> "cloud-init: Sets DNS search domains for a container. Create will automatically use the setting from the host if neither searchdomain nor nameserver are set.",
566 type
=> 'string', format
=> 'address-list',
567 description
=> "cloud-init: Sets DNS server IP address for a container. Create will automatically use the setting from the host if neither searchdomain nor nameserver are set.",
572 format
=> 'urlencoded',
573 description
=> "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
577 # what about other qemu settings ?
579 #machine => 'string',
592 ##soundhw => 'string',
594 while (my ($k, $v) = each %$confdesc) {
595 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
598 my $MAX_IDE_DISKS = 4;
599 my $MAX_SCSI_DISKS = 14;
600 my $MAX_VIRTIO_DISKS = 16;
601 my $MAX_SATA_DISKS = 6;
602 my $MAX_USB_DEVICES = 5;
604 my $MAX_UNUSED_DISKS = 8;
605 my $MAX_HOSTPCI_DEVICES = 4;
606 my $MAX_SERIAL_PORTS = 4;
607 my $MAX_PARALLEL_PORTS = 3;
613 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
614 description
=> "CPUs accessing this NUMA node.",
615 format_description
=> "id[-id];...",
619 description
=> "Amount of memory this NUMA node provides.",
624 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
625 description
=> "Host NUMA nodes to use.",
626 format_description
=> "id[-id];...",
631 enum
=> [qw(preferred bind interleave)],
632 description
=> "NUMA allocation policy.",
636 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
639 type
=> 'string', format
=> $numa_fmt,
640 description
=> "NUMA topology.",
642 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
644 for (my $i = 0; $i < $MAX_NUMA; $i++) {
645 $confdesc->{"numa$i"} = $numadesc;
648 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
649 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
650 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
651 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
653 my $net_fmt_bridge_descr = <<__EOD__;
654 Bridge to attach the network device to. The Proxmox VE standard bridge
657 If you do not specify a bridge, we create a kvm user (NATed) network
658 device, which provides DHCP and DNS services. The following addresses
665 The DHCP server assign addresses to the guest starting from 10.0.2.15.
671 pattern
=> qr/[0-9a-f]{2}(?::[0-9a-f]{2}){5}/i,
672 description
=> "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
673 format_description
=> "XX:XX:XX:XX:XX:XX",
678 description
=> "Network Card Model. The 'virtio' model provides the best performance with very low CPU overhead. If your guest does not support this driver, it is usually best to use 'e1000'.",
679 enum
=> $nic_model_list,
682 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
685 description
=> $net_fmt_bridge_descr,
686 format_description
=> 'bridge',
691 minimum
=> 0, maximum
=> 16,
692 description
=> 'Number of packet queues to be used on the device.',
698 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
703 minimum
=> 1, maximum
=> 4094,
704 description
=> 'VLAN tag to apply to packets on this interface.',
709 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
710 description
=> 'VLAN trunks to pass through this interface.',
711 format_description
=> 'vlanid[;vlanid...]',
716 description
=> 'Whether this interface should be protected by the firewall.',
721 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
728 type
=> 'string', format
=> $net_fmt,
729 description
=> "Specify network devices.",
732 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
737 format
=> 'pve-ipv4-config',
738 format_description
=> 'IPv4Format/CIDR',
739 description
=> 'IPv4 address in CIDR format.',
746 format_description
=> 'GatewayIPv4',
747 description
=> 'Default gateway for IPv4 traffic.',
753 format
=> 'pve-ipv6-config',
754 format_description
=> 'IPv6Format/CIDR',
755 description
=> 'IPv6 address in CIDR format.',
762 format_description
=> 'GatewayIPv6',
763 description
=> 'Default gateway for IPv6 traffic.',
768 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
771 type
=> 'string', format
=> 'pve-qm-ipconfig',
772 description
=> <<'EODESCR',
773 cloud-init: Specify IP addresses and gateways for the corresponding interface.
775 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
777 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided.
778 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration.
780 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4.
783 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
785 for (my $i = 0; $i < $MAX_NETS; $i++) {
786 $confdesc->{"net$i"} = $netdesc;
787 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
790 foreach my $key (keys %$confdesc_cloudinit) {
791 $confdesc->{$key} = $confdesc_cloudinit->{$key};
794 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
795 sub verify_volume_id_or_qm_path
{
796 my ($volid, $noerr) = @_;
798 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
802 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
803 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
805 return undef if $noerr;
813 my %drivedesc_base = (
814 volume
=> { alias
=> 'file' },
817 format
=> 'pve-volume-id-or-qm-path',
819 format_description
=> 'volume',
820 description
=> "The drive's backing volume.",
824 enum
=> [qw(cdrom disk)],
825 description
=> "The drive's media type.",
831 description
=> "Force the drive's physical geometry to have a specific cylinder count.",
836 description
=> "Force the drive's physical geometry to have a specific head count.",
841 description
=> "Force the drive's physical geometry to have a specific sector count.",
846 enum
=> [qw(none lba auto)],
847 description
=> "Force disk geometry bios translation mode.",
852 description
=> "Controls qemu's snapshot mode feature."
853 . " If activated, changes made to the disk are temporary and will"
854 . " be discarded when the VM is shutdown.",
859 enum
=> [qw(none writethrough writeback unsafe directsync)],
860 description
=> "The drive's cache mode",
863 format
=> get_standard_option
('pve-qm-image-format'),
866 format
=> 'disk-size',
867 format_description
=> 'DiskSize',
868 description
=> "Disk size. This is purely informational and has no effect.",
873 description
=> "Whether the drive should be included when making backups.",
878 description
=> 'Whether the drive should considered for replication jobs.',
884 enum
=> [qw(ignore report stop)],
885 description
=> 'Read error action.',
890 enum
=> [qw(enospc ignore report stop)],
891 description
=> 'Write error action.',
896 enum
=> [qw(native threads)],
897 description
=> 'AIO type to use.',
902 enum
=> [qw(ignore on)],
903 description
=> 'Controls whether to pass discard/trim requests to the underlying storage.',
908 description
=> 'Controls whether to detect and try to optimize writes of zeroes.',
913 format
=> 'urlencoded',
914 format_description
=> 'serial',
915 maxLength
=> 20*3, # *3 since it's %xx url enoded
916 description
=> "The drive's reported serial number, url-encoded, up to 20 bytes long.",
921 description
=> 'Mark this locally-managed volume as available on all nodes',
922 verbose_description
=> "Mark this locally-managed volume as available on all nodes.\n\nWARNING: This option does not share the volume automatically, it assumes it is shared already!",
928 my %iothread_fmt = ( iothread
=> {
930 description
=> "Whether to use iothreads for this drive",
937 format
=> 'urlencoded',
938 format_description
=> 'model',
939 maxLength
=> 40*3, # *3 since it's %xx url enoded
940 description
=> "The drive's reported model name, url-encoded, up to 40 bytes long.",
948 description
=> "Number of queues.",
954 my %scsiblock_fmt = (
957 description
=> "whether to use scsi-block for full passthrough of host block device\n\nWARNING: can lead to I/O errors in combination with low memory or high memory fragmentation on host",
963 my $add_throttle_desc = sub {
964 my ($key, $type, $what, $unit, $longunit, $minimum) = @_;
967 format_description
=> $unit,
968 description
=> "Maximum $what in $longunit.",
971 $d->{minimum
} = $minimum if defined($minimum);
972 $drivedesc_base{$key} = $d;
974 # throughput: (leaky bucket)
975 $add_throttle_desc->('bps', 'integer', 'r/w speed', 'bps', 'bytes per second');
976 $add_throttle_desc->('bps_rd', 'integer', 'read speed', 'bps', 'bytes per second');
977 $add_throttle_desc->('bps_wr', 'integer', 'write speed', 'bps', 'bytes per second');
978 $add_throttle_desc->('mbps', 'number', 'r/w speed', 'mbps', 'megabytes per second');
979 $add_throttle_desc->('mbps_rd', 'number', 'read speed', 'mbps', 'megabytes per second');
980 $add_throttle_desc->('mbps_wr', 'number', 'write speed', 'mbps', 'megabytes per second');
981 $add_throttle_desc->('iops', 'integer', 'r/w I/O', 'iops', 'operations per second');
982 $add_throttle_desc->('iops_rd', 'integer', 'read I/O', 'iops', 'operations per second');
983 $add_throttle_desc->('iops_wr', 'integer', 'write I/O', 'iops', 'operations per second');
985 # pools: (pool of IO before throttling starts taking effect)
986 $add_throttle_desc->('mbps_max', 'number', 'unthrottled r/w pool', 'mbps', 'megabytes per second');
987 $add_throttle_desc->('mbps_rd_max', 'number', 'unthrottled read pool', 'mbps', 'megabytes per second');
988 $add_throttle_desc->('mbps_wr_max', 'number', 'unthrottled write pool', 'mbps', 'megabytes per second');
989 $add_throttle_desc->('iops_max', 'integer', 'unthrottled r/w I/O pool', 'iops', 'operations per second');
990 $add_throttle_desc->('iops_rd_max', 'integer', 'unthrottled read I/O pool', 'iops', 'operations per second');
991 $add_throttle_desc->('iops_wr_max', 'integer', 'unthrottled write I/O pool', 'iops', 'operations per second');
994 $add_throttle_desc->('bps_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
995 $add_throttle_desc->('bps_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
996 $add_throttle_desc->('bps_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
997 $add_throttle_desc->('iops_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
998 $add_throttle_desc->('iops_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
999 $add_throttle_desc->('iops_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1002 $drivedesc_base{'bps_rd_length'} = { alias
=> 'bps_rd_max_length' };
1003 $drivedesc_base{'bps_wr_length'} = { alias
=> 'bps_wr_max_length' };
1004 $drivedesc_base{'iops_rd_length'} = { alias
=> 'iops_rd_max_length' };
1005 $drivedesc_base{'iops_wr_length'} = { alias
=> 'iops_wr_max_length' };
1011 PVE
::JSONSchema
::register_format
("pve-qm-ide", $ide_fmt);
1015 type
=> 'string', format
=> $ide_fmt,
1016 description
=> "Use volume as IDE hard disk or CD-ROM (n is 0 to " .($MAX_IDE_DISKS -1) . ").",
1018 PVE
::JSONSchema
::register_standard_option
("pve-qm-ide", $idedesc);
1028 type
=> 'string', format
=> $scsi_fmt,
1029 description
=> "Use volume as SCSI hard disk or CD-ROM (n is 0 to " . ($MAX_SCSI_DISKS - 1) . ").",
1031 PVE
::JSONSchema
::register_standard_option
("pve-qm-scsi", $scsidesc);
1038 type
=> 'string', format
=> $sata_fmt,
1039 description
=> "Use volume as SATA hard disk or CD-ROM (n is 0 to " . ($MAX_SATA_DISKS - 1). ").",
1041 PVE
::JSONSchema
::register_standard_option
("pve-qm-sata", $satadesc);
1049 type
=> 'string', format
=> $virtio_fmt,
1050 description
=> "Use volume as VIRTIO hard disk (n is 0 to " . ($MAX_VIRTIO_DISKS - 1) . ").",
1052 PVE
::JSONSchema
::register_standard_option
("pve-qm-virtio", $virtiodesc);
1054 my $alldrive_fmt = {
1063 volume
=> { alias
=> 'file' },
1066 format
=> 'pve-volume-id-or-qm-path',
1068 format_description
=> 'volume',
1069 description
=> "The drive's backing volume.",
1071 format
=> get_standard_option
('pve-qm-image-format'),
1074 format
=> 'disk-size',
1075 format_description
=> 'DiskSize',
1076 description
=> "Disk size. This is purely informational and has no effect.",
1081 my $efidisk_desc = {
1083 type
=> 'string', format
=> $efidisk_fmt,
1084 description
=> "Configure a Disk for storing EFI vars",
1087 PVE
::JSONSchema
::register_standard_option
("pve-qm-efidisk", $efidisk_desc);
1092 type
=> 'string', format
=> 'pve-qm-usb-device',
1093 format_description
=> 'HOSTUSBDEVICE|spice',
1094 description
=> <<EODESCR,
1095 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1097 'bus-port(.port)*' (decimal numbers) or
1098 'vendor_id:product_id' (hexadeciaml numbers) or
1101 You can use the 'lsusb -t' command to list existing usb devices.
1103 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1105 The value 'spice' can be used to add a usb redirection devices for spice.
1111 description
=> "Specifies whether if given host option is a USB3 device or port (this does currently not work reliably with spice redirection and is then ignored).",
1118 type
=> 'string', format
=> $usb_fmt,
1119 description
=> "Configure an USB device (n is 0 to 4).",
1121 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
1123 # NOTE: the match-groups of this regex are used in parse_hostpci
1124 my $PCIRE = qr/([a-f0-9]{2}:[a-f0-9]{2})(?:\.([a-f0-9]))?/;
1129 pattern
=> qr/$PCIRE(;$PCIRE)*/,
1130 format_description
=> 'HOSTPCIID[;HOSTPCIID2...]',
1131 description
=> <<EODESCR,
1132 Host PCI device pass through. The PCI ID of a host's PCI device or a list
1133 of PCI virtual functions of the host. HOSTPCIID syntax is:
1135 'bus:dev.func' (hexadecimal numbers)
1137 You can us the 'lspci' command to list existing PCI devices.
1142 description
=> "Specify whether or not the device's ROM will be visible in the guest's memory map.",
1148 pattern
=> '[^,;]+',
1149 format_description
=> 'string',
1150 description
=> "Custom pci device rom filename (must be located in /usr/share/kvm/).",
1155 description
=> "Choose the PCI-express bus (needs the 'q35' machine model).",
1161 description
=> "Enable vfio-vga device support.",
1166 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', $hostpci_fmt);
1170 type
=> 'string', format
=> 'pve-qm-hostpci',
1171 description
=> "Map host PCI devices into guest.",
1172 verbose_description
=> <<EODESCR,
1173 Map host PCI devices into guest.
1175 NOTE: This option allows direct access to host hardware. So it is no longer
1176 possible to migrate such machines - use with special care.
1178 CAUTION: Experimental! User reported problems with this option.
1181 PVE
::JSONSchema
::register_standard_option
("pve-qm-hostpci", $hostpcidesc);
1186 pattern
=> '(/dev/.+|socket)',
1187 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1188 verbose_description
=> <<EODESCR,
1189 Create a serial device inside the VM (n is 0 to 3), and pass through a
1190 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1191 host side (use 'qm terminal' to open a terminal connection).
1193 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
1195 CAUTION: Experimental! User reported problems with this option.
1202 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1203 description
=> "Map host parallel devices (n is 0 to 2).",
1204 verbose_description
=> <<EODESCR,
1205 Map host parallel devices (n is 0 to 2).
1207 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1209 CAUTION: Experimental! User reported problems with this option.
1213 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1214 $confdesc->{"parallel$i"} = $paralleldesc;
1217 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1218 $confdesc->{"serial$i"} = $serialdesc;
1221 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
1222 $confdesc->{"hostpci$i"} = $hostpcidesc;
1225 for (my $i = 0; $i < $MAX_IDE_DISKS; $i++) {
1226 $drivename_hash->{"ide$i"} = 1;
1227 $confdesc->{"ide$i"} = $idedesc;
1230 for (my $i = 0; $i < $MAX_SATA_DISKS; $i++) {
1231 $drivename_hash->{"sata$i"} = 1;
1232 $confdesc->{"sata$i"} = $satadesc;
1235 for (my $i = 0; $i < $MAX_SCSI_DISKS; $i++) {
1236 $drivename_hash->{"scsi$i"} = 1;
1237 $confdesc->{"scsi$i"} = $scsidesc ;
1240 for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++) {
1241 $drivename_hash->{"virtio$i"} = 1;
1242 $confdesc->{"virtio$i"} = $virtiodesc;
1245 $drivename_hash->{efidisk0
} = 1;
1246 $confdesc->{efidisk0
} = $efidisk_desc;
1248 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1249 $confdesc->{"usb$i"} = $usbdesc;
1254 type
=> 'string', format
=> 'pve-volume-id',
1255 description
=> "Reference to unused volumes. This is used internally, and should not be modified manually.",
1258 for (my $i = 0; $i < $MAX_UNUSED_DISKS; $i++) {
1259 $confdesc->{"unused$i"} = $unuseddesc;
1262 my $kvm_api_version = 0;
1266 return $kvm_api_version if $kvm_api_version;
1268 my $fh = IO
::File-
>new("</dev/kvm") ||
1271 if (my $v = $fh->ioctl(KVM_GET_API_VERSION
(), 0)) {
1272 $kvm_api_version = $v;
1277 return $kvm_api_version;
1280 my $kvm_user_version;
1282 sub kvm_user_version
{
1284 return $kvm_user_version if $kvm_user_version;
1286 $kvm_user_version = 'unknown';
1290 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1291 $kvm_user_version = $2;
1295 eval { run_command
("kvm -version", outfunc
=> $code); };
1298 return $kvm_user_version;
1302 my $kernel_has_vhost_net = -c
'/dev/vhost-net';
1304 sub valid_drive_names
{
1305 # order is important - used to autoselect boot disk
1306 return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
1307 (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
1308 (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))),
1309 (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))),
1313 sub is_valid_drivename
{
1316 return defined($drivename_hash->{$dev});
1321 return defined($confdesc->{$key});
1325 return $nic_model_list;
1328 sub os_list_description
{
1332 wxp
=> 'Windows XP',
1333 w2k
=> 'Windows 2000',
1334 w2k3
=>, 'Windows 2003',
1335 w2k8
=> 'Windows 2008',
1336 wvista
=> 'Windows Vista',
1337 win7
=> 'Windows 7',
1338 win8
=> 'Windows 8/2012',
1339 win10
=> 'Windows 10/2016',
1347 sub get_cdrom_path
{
1349 return $cdrom_path if $cdrom_path;
1351 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1352 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1353 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1357 my ($storecfg, $vmid, $cdrom) = @_;
1359 if ($cdrom eq 'cdrom') {
1360 return get_cdrom_path
();
1361 } elsif ($cdrom eq 'none') {
1363 } elsif ($cdrom =~ m
|^/|) {
1366 return PVE
::Storage
::path
($storecfg, $cdrom);
1370 # try to convert old style file names to volume IDs
1371 sub filename_to_volume_id
{
1372 my ($vmid, $file, $media) = @_;
1374 if (!($file eq 'none' || $file eq 'cdrom' ||
1375 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1377 return undef if $file =~ m
|/|;
1379 if ($media && $media eq 'cdrom') {
1380 $file = "local:iso/$file";
1382 $file = "local:$vmid/$file";
1389 sub verify_media_type
{
1390 my ($opt, $vtype, $media) = @_;
1395 if ($media eq 'disk') {
1397 } elsif ($media eq 'cdrom') {
1400 die "internal error";
1403 return if ($vtype eq $etype);
1405 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1408 sub cleanup_drive_path
{
1409 my ($opt, $storecfg, $drive) = @_;
1411 # try to convert filesystem paths to volume IDs
1413 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1414 ($drive->{file
} !~ m
|^/dev/.+|) &&
1415 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1416 ($drive->{file
} !~ m/^\d+$/)) {
1417 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1418 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1419 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1420 verify_media_type
($opt, $vtype, $drive->{media
});
1421 $drive->{file
} = $volid;
1424 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1427 sub parse_hotplug_features
{
1432 return $res if $data eq '0';
1434 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1436 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1437 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1440 die "invalid hotplug feature '$feature'\n";
1446 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1447 sub pve_verify_hotplug_features
{
1448 my ($value, $noerr) = @_;
1450 return $value if parse_hotplug_features
($value);
1452 return undef if $noerr;
1454 die "unable to parse hotplug option\n";
1457 # ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
1458 # [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
1459 # [,rerror=ignore|report|stop][,werror=enospc|ignore|report|stop]
1460 # [,aio=native|threads][,discard=ignore|on][,detect_zeroes=on|off]
1461 # [,iothread=on][,serial=serial][,model=model]
1464 my ($key, $data) = @_;
1466 my ($interface, $index);
1468 if ($key =~ m/^([^\d]+)(\d+)$/) {
1475 my $desc = $key =~ /^unused\d+$/ ?
$alldrive_fmt
1476 : $confdesc->{$key}->{format
};
1478 warn "invalid drive key: $key\n";
1481 my $res = eval { PVE
::JSONSchema
::parse_property_string
($desc, $data) };
1482 return undef if !$res;
1483 $res->{interface
} = $interface;
1484 $res->{index} = $index;
1487 foreach my $opt (qw(bps bps_rd bps_wr)) {
1488 if (my $bps = defined(delete $res->{$opt})) {
1489 if (defined($res->{"m$opt"})) {
1490 warn "both $opt and m$opt specified\n";
1494 $res->{"m$opt"} = sprintf("%.3f", $bps / (1024*1024.0));
1498 # can't use the schema's 'requires' because of the mbps* => bps* "transforming aliases"
1499 for my $requirement (
1500 [mbps_max
=> 'mbps'],
1501 [mbps_rd_max
=> 'mbps_rd'],
1502 [mbps_wr_max
=> 'mbps_wr'],
1503 [miops_max
=> 'miops'],
1504 [miops_rd_max
=> 'miops_rd'],
1505 [miops_wr_max
=> 'miops_wr'],
1506 [bps_max_length
=> 'mbps_max'],
1507 [bps_rd_max_length
=> 'mbps_rd_max'],
1508 [bps_wr_max_length
=> 'mbps_wr_max'],
1509 [iops_max_length
=> 'iops_max'],
1510 [iops_rd_max_length
=> 'iops_rd_max'],
1511 [iops_wr_max_length
=> 'iops_wr_max']) {
1512 my ($option, $requires) = @$requirement;
1513 if ($res->{$option} && !$res->{$requires}) {
1514 warn "$option requires $requires\n";
1519 return undef if $error;
1521 return undef if $res->{mbps_rd
} && $res->{mbps
};
1522 return undef if $res->{mbps_wr
} && $res->{mbps
};
1523 return undef if $res->{iops_rd
} && $res->{iops
};
1524 return undef if $res->{iops_wr
} && $res->{iops
};
1526 if ($res->{media
} && ($res->{media
} eq 'cdrom')) {
1527 return undef if $res->{snapshot
} || $res->{trans
} || $res->{format
};
1528 return undef if $res->{heads
} || $res->{secs
} || $res->{cyls
};
1529 return undef if $res->{interface
} eq 'virtio';
1532 if (my $size = $res->{size
}) {
1533 return undef if !defined($res->{size
} = PVE
::JSONSchema
::parse_size
($size));
1540 my ($vmid, $drive) = @_;
1541 my $data = { %$drive };
1542 delete $data->{$_} for qw(index interface);
1543 return PVE
::JSONSchema
::print_property_string
($data, $alldrive_fmt);
1547 my($fh, $noerr) = @_;
1550 my $SG_GET_VERSION_NUM = 0x2282;
1552 my $versionbuf = "\x00" x
8;
1553 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1555 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1558 my $version = unpack("I", $versionbuf);
1559 if ($version < 30000) {
1560 die "scsi generic interface too old\n" if !$noerr;
1564 my $buf = "\x00" x
36;
1565 my $sensebuf = "\x00" x
8;
1566 my $cmd = pack("C x3 C x1", 0x12, 36);
1568 # see /usr/include/scsi/sg.h
1569 my $sg_io_hdr_t = "i i C C s I P P P I I i P C C C C S S i I I";
1571 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1572 length($sensebuf), 0, length($buf), $buf,
1573 $cmd, $sensebuf, 6000);
1575 $ret = ioctl($fh, $SG_IO, $packet);
1577 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1581 my @res = unpack($sg_io_hdr_t, $packet);
1582 if ($res[17] || $res[18]) {
1583 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1588 (my $byte0, my $byte1, $res->{vendor
},
1589 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1591 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1592 $res->{type
} = $byte0 & 31;
1600 my $fh = IO
::File-
>new("+<$path") || return undef;
1601 my $res = scsi_inquiry
($fh, 1);
1607 sub machine_type_is_q35
{
1610 return $conf->{machine
} && ($conf->{machine
} =~ m/q35/) ?
1 : 0;
1613 sub print_tabletdevice_full
{
1616 my $q35 = machine_type_is_q35
($conf);
1618 # we use uhci for old VMs because tablet driver was buggy in older qemu
1619 my $usbbus = $q35 ?
"ehci" : "uhci";
1621 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1624 sub print_drivedevice_full
{
1625 my ($storecfg, $conf, $vmid, $drive, $bridges) = @_;
1630 if ($drive->{interface
} eq 'virtio') {
1631 my $pciaddr = print_pci_addr
("$drive->{interface}$drive->{index}", $bridges);
1632 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1633 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread
};
1634 } elsif ($drive->{interface
} eq 'scsi') {
1636 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1637 my $unit = $drive->{index} % $maxdev;
1638 my $devicetype = 'hd';
1640 if (drive_is_cdrom
($drive)) {
1643 if ($drive->{file
} =~ m
|^/|) {
1644 $path = $drive->{file
};
1645 if (my $info = path_is_scsi
($path)) {
1646 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1647 $devicetype = 'block';
1648 } elsif ($info->{type
} == 1) { # tape
1649 $devicetype = 'generic';
1653 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1656 if($path =~ m/^iscsi\:\/\
//){
1657 $devicetype = 'generic';
1661 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1662 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1664 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,channel=0,scsi-id=0,lun=$drive->{index},drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1667 } elsif ($drive->{interface
} eq 'ide'){
1669 my $controller = int($drive->{index} / $maxdev);
1670 my $unit = $drive->{index} % $maxdev;
1671 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1673 $device = "ide-$devicetype,bus=ide.$controller,unit=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1674 if ($devicetype eq 'hd' && (my $model = $drive->{model
})) {
1675 $model = URI
::Escape
::uri_unescape
($model);
1676 $device .= ",model=$model";
1678 } elsif ($drive->{interface
} eq 'sata'){
1679 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
1680 my $unit = $drive->{index} % $MAX_SATA_DISKS;
1681 $device = "ide-drive,bus=ahci$controller.$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1682 } elsif ($drive->{interface
} eq 'usb') {
1684 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1686 die "unsupported interface type";
1689 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1694 sub get_initiator_name
{
1697 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return undef;
1698 while (defined(my $line = <$fh>)) {
1699 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1708 sub print_drive_full
{
1709 my ($storecfg, $vmid, $drive) = @_;
1712 my $volid = $drive->{file
};
1715 if (drive_is_cdrom
($drive)) {
1716 $path = get_iso_path
($storecfg, $vmid, $volid);
1718 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1720 $path = PVE
::Storage
::path
($storecfg, $volid);
1721 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1722 $format = qemu_img_format
($scfg, $volname);
1730 my @qemu_drive_options = qw(heads secs cyls trans media format cache rerror werror aio discard);
1731 foreach my $o (@qemu_drive_options) {
1732 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1735 # snapshot only accepts on|off
1736 if (defined($drive->{snapshot
})) {
1737 my $v = $drive->{snapshot
} ?
'on' : 'off';
1738 $opts .= ",snapshot=$v";
1741 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1742 my ($dir, $qmpname) = @$type;
1743 if (my $v = $drive->{"mbps$dir"}) {
1744 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1746 if (my $v = $drive->{"mbps${dir}_max"}) {
1747 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1749 if (my $v = $drive->{"bps${dir}_max_length"}) {
1750 $opts .= ",throttling.bps$qmpname-max-length=$v";
1752 if (my $v = $drive->{"iops${dir}"}) {
1753 $opts .= ",throttling.iops$qmpname=$v";
1755 if (my $v = $drive->{"iops${dir}_max"}) {
1756 $opts .= ",throttling.iops$qmpname-max=$v";
1758 if (my $v = $drive->{"iops${dir}_max_length"}) {
1759 $opts .= ",throttling.iops$qmpname-max-length=$v";
1763 if (my $serial = $drive->{serial
}) {
1764 $serial = URI
::Escape
::uri_unescape
($serial);
1765 $opts .= ",serial=$serial";
1768 $opts .= ",format=$format" if $format && !$drive->{format
};
1770 my $cache_direct = 0;
1772 if (my $cache = $drive->{cache
}) {
1773 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1774 } elsif (!drive_is_cdrom
($drive)) {
1775 $opts .= ",cache=none";
1779 # aio native works only with O_DIRECT
1780 if (!$drive->{aio
}) {
1782 $opts .= ",aio=native";
1784 $opts .= ",aio=threads";
1788 if (!drive_is_cdrom
($drive)) {
1790 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1791 $detectzeroes = 'off';
1792 } elsif ($drive->{discard
}) {
1793 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1795 # This used to be our default with discard not being specified:
1796 $detectzeroes = 'on';
1798 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1801 my $pathinfo = $path ?
"file=$path," : '';
1803 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1806 sub print_netdevice_full
{
1807 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files) = @_;
1809 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
1811 my $device = $net->{model
};
1812 if ($net->{model
} eq 'virtio') {
1813 $device = 'virtio-net-pci';
1816 my $pciaddr = print_pci_addr
("$netid", $bridges);
1817 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1818 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1819 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1820 my $vectors = $net->{queues
} * 2 + 2;
1821 $tmpstr .= ",vectors=$vectors,mq=on";
1823 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1825 if ($use_old_bios_files) {
1827 if ($device eq 'virtio-net-pci') {
1828 $romfile = 'pxe-virtio.rom';
1829 } elsif ($device eq 'e1000') {
1830 $romfile = 'pxe-e1000.rom';
1831 } elsif ($device eq 'ne2k') {
1832 $romfile = 'pxe-ne2k_pci.rom';
1833 } elsif ($device eq 'pcnet') {
1834 $romfile = 'pxe-pcnet.rom';
1835 } elsif ($device eq 'rtl8139') {
1836 $romfile = 'pxe-rtl8139.rom';
1838 $tmpstr .= ",romfile=$romfile" if $romfile;
1844 sub print_netdev_full
{
1845 my ($vmid, $conf, $net, $netid, $hotplug) = @_;
1848 if ($netid =~ m/^net(\d+)$/) {
1852 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1854 my $ifname = "tap${vmid}i$i";
1856 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1857 die "interface name '$ifname' is too long (max 15 character)\n"
1858 if length($ifname) >= 16;
1860 my $vhostparam = '';
1861 $vhostparam = ',vhost=on' if $kernel_has_vhost_net && $net->{model
} eq 'virtio';
1863 my $vmname = $conf->{name
} || "vm$vmid";
1866 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1868 if ($net->{bridge
}) {
1869 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1871 $netdev = "type=user,id=$netid,hostname=$vmname";
1874 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1880 sub print_cpu_device
{
1881 my ($conf, $id) = @_;
1883 my $kvm = $conf->{kvm
} // 1;
1884 my $cpu = $kvm ?
"kvm64" : "qemu64";
1885 if (my $cputype = $conf->{cpu
}) {
1886 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
1887 or die "Cannot parse cpu description: $cputype\n";
1888 $cpu = $cpuconf->{cputype
};
1891 my $cores = $conf->{cores
} || 1;
1893 my $current_core = ($id - 1) % $cores;
1894 my $current_socket = int(($id - 1 - $current_core)/$cores);
1896 return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
1899 sub drive_is_cloudinit
{
1901 return $drive->{file
} =~ m
@[:/]vm-\d
+-cloudinit
(?
:\
.$QEMU_FORMAT_RE)?
$@;
1904 sub drive_is_cdrom
{
1905 my ($drive, $exclude_cloudinit) = @_;
1907 return 0 if $exclude_cloudinit && drive_is_cloudinit
($drive);
1909 return $drive && $drive->{media
} && ($drive->{media
} eq 'cdrom');
1913 sub parse_number_sets
{
1916 foreach my $part (split(/;/, $set)) {
1917 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
1918 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
1919 push @$res, [ $1, $2 ];
1921 die "invalid range: $part\n";
1930 my $res = PVE
::JSONSchema
::parse_property_string
($numa_fmt, $data);
1931 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
1932 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
1939 return undef if !$value;
1941 my $res = PVE
::JSONSchema
::parse_property_string
($hostpci_fmt, $value);
1943 my @idlist = split(/;/, $res->{host
});
1944 delete $res->{host
};
1945 foreach my $id (@idlist) {
1946 if ($id =~ /^$PCIRE$/) {
1948 push @{$res->{pciid
}}, { id
=> $1, function
=> $2 };
1950 my $pcidevices = lspci
($1);
1951 $res->{pciid
} = $pcidevices->{$1};
1954 # should have been caught by parse_property_string already
1955 die "failed to parse PCI id: $id\n";
1961 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1965 my $res = eval { PVE
::JSONSchema
::parse_property_string
($net_fmt, $data) };
1970 if (!defined($res->{macaddr
})) {
1971 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
1972 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
1974 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
() if !defined($res->{macaddr
});
1978 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
1979 sub parse_ipconfig
{
1982 my $res = eval { PVE
::JSONSchema
::parse_property_string
($ipconfig_fmt, $data) };
1988 if ($res->{gw
} && !$res->{ip
}) {
1989 warn 'gateway specified without specifying an IP address';
1992 if ($res->{gw6
} && !$res->{ip6
}) {
1993 warn 'IPv6 gateway specified without specifying an IPv6 address';
1996 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
1997 warn 'gateway specified together with DHCP';
2000 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
2002 warn "IPv6 gateway specified together with $res->{ip6} address";
2006 if (!$res->{ip
} && !$res->{ip6
}) {
2007 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
2016 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
2019 sub add_random_macs
{
2020 my ($settings) = @_;
2022 foreach my $opt (keys %$settings) {
2023 next if $opt !~ m/^net(\d+)$/;
2024 my $net = parse_net
($settings->{$opt});
2026 $settings->{$opt} = print_net
($net);
2030 sub vm_is_volid_owner
{
2031 my ($storecfg, $vmid, $volid) = @_;
2033 if ($volid !~ m
|^/|) {
2035 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
2036 if ($owner && ($owner == $vmid)) {
2044 sub split_flagged_list
{
2045 my $text = shift || '';
2046 $text =~ s/[,;]/ /g;
2048 return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
2051 sub join_flagged_list
{
2052 my ($how, $lst) = @_;
2053 join $how, map { $lst->{$_} . $_ } keys %$lst;
2056 sub vmconfig_delete_pending_option
{
2057 my ($conf, $key, $force) = @_;
2059 delete $conf->{pending
}->{$key};
2060 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2061 $pending_delete_hash->{$key} = $force ?
'!' : '';
2062 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2065 sub vmconfig_undelete_pending_option
{
2066 my ($conf, $key) = @_;
2068 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2069 delete $pending_delete_hash->{$key};
2071 if (%$pending_delete_hash) {
2072 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2074 delete $conf->{pending
}->{delete};
2078 sub vmconfig_register_unused_drive
{
2079 my ($storecfg, $vmid, $conf, $drive) = @_;
2081 if (drive_is_cloudinit
($drive)) {
2082 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
2084 } elsif (!drive_is_cdrom
($drive)) {
2085 my $volid = $drive->{file
};
2086 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
2087 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
2092 sub vmconfig_cleanup_pending
{
2095 # remove pending changes when nothing changed
2097 foreach my $opt (keys %{$conf->{pending
}}) {
2098 if (defined($conf->{$opt}) && ($conf->{pending
}->{$opt} eq $conf->{$opt})) {
2100 delete $conf->{pending
}->{$opt};
2104 my $current_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2105 my $pending_delete_hash = {};
2106 while (my ($opt, $force) = each %$current_delete_hash) {
2107 if (defined($conf->{$opt})) {
2108 $pending_delete_hash->{$opt} = $force;
2114 if (%$pending_delete_hash) {
2115 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2117 delete $conf->{pending
}->{delete};
2123 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
2127 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2128 format_description
=> 'UUID',
2129 description
=> "Set SMBIOS1 UUID.",
2135 format_description
=> 'string',
2136 description
=> "Set SMBIOS1 version.",
2142 format_description
=> 'string',
2143 description
=> "Set SMBIOS1 serial number.",
2149 format_description
=> 'string',
2150 description
=> "Set SMBIOS1 manufacturer.",
2156 format_description
=> 'string',
2157 description
=> "Set SMBIOS1 product ID.",
2163 format_description
=> 'string',
2164 description
=> "Set SMBIOS1 SKU string.",
2170 format_description
=> 'string',
2171 description
=> "Set SMBIOS1 family string.",
2179 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_fmt, $data) };
2186 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
2189 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
2191 PVE
::JSONSchema
::register_format
('pve-qm-bootdisk', \
&verify_bootdisk
);
2192 sub verify_bootdisk
{
2193 my ($value, $noerr) = @_;
2195 return $value if is_valid_drivename
($value);
2197 return undef if $noerr;
2199 die "invalid boot disk '$value'\n";
2202 sub parse_watchdog
{
2205 return undef if !$value;
2207 my $res = eval { PVE
::JSONSchema
::parse_property_string
($watchdog_fmt, $value) };
2212 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
2213 sub verify_usb_device
{
2214 my ($value, $noerr) = @_;
2216 return $value if parse_usb_device
($value);
2218 return undef if $noerr;
2220 die "unable to parse usb device\n";
2223 # add JSON properties for create and set function
2224 sub json_config_properties
{
2227 foreach my $opt (keys %$confdesc) {
2228 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate';
2229 $prop->{$opt} = $confdesc->{$opt};
2235 # return copy of $confdesc_cloudinit to generate documentation
2236 sub cloudinit_config_properties
{
2238 return dclone
($confdesc_cloudinit);
2242 my ($key, $value) = @_;
2244 die "unknown setting '$key'\n" if !$confdesc->{$key};
2246 my $type = $confdesc->{$key}->{type
};
2248 if (!defined($value)) {
2249 die "got undefined value\n";
2252 if ($value =~ m/[\n\r]/) {
2253 die "property contains a line feed\n";
2256 if ($type eq 'boolean') {
2257 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2258 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2259 die "type check ('boolean') failed - got '$value'\n";
2260 } elsif ($type eq 'integer') {
2261 return int($1) if $value =~ m/^(\d+)$/;
2262 die "type check ('integer') failed - got '$value'\n";
2263 } elsif ($type eq 'number') {
2264 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2265 die "type check ('number') failed - got '$value'\n";
2266 } elsif ($type eq 'string') {
2267 if (my $fmt = $confdesc->{$key}->{format
}) {
2268 PVE
::JSONSchema
::check_format
($fmt, $value);
2271 $value =~ s/^\"(.*)\"$/$1/;
2274 die "internal error"
2278 sub check_iommu_support
{
2279 #fixme : need to check IOMMU support
2280 #http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM
2290 my $conf = PVE
::QemuConfig-
>config_file($vmid);
2291 utime undef, undef, $conf;
2295 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
2297 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
2299 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2301 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2303 if ($conf->{template
}) {
2304 # check if any base image is still used by a linked clone
2305 foreach_drive
($conf, sub {
2306 my ($ds, $drive) = @_;
2308 return if drive_is_cdrom
($drive);
2310 my $volid = $drive->{file
};
2312 return if !$volid || $volid =~ m
|^/|;
2314 die "base volume '$volid' is still in use by linked cloned\n"
2315 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2320 # only remove disks owned by this VM
2321 foreach_drive
($conf, sub {
2322 my ($ds, $drive) = @_;
2324 return if drive_is_cdrom
($drive, 1);
2326 my $volid = $drive->{file
};
2328 return if !$volid || $volid =~ m
|^/|;
2330 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2331 return if !$path || !$owner || ($owner != $vmid);
2334 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2336 warn "Could not remove disk '$volid', check manually: $@" if $@;
2340 if ($keep_empty_config) {
2341 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
2346 # also remove unused disk
2348 my $dl = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
2351 PVE
::Storage
::foreach_volid
($dl, sub {
2352 my ($volid, $sid, $volname, $d) = @_;
2353 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2362 sub parse_vm_config
{
2363 my ($filename, $raw) = @_;
2365 return undef if !defined($raw);
2368 digest
=> Digest
::SHA
::sha1_hex
($raw),
2373 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2374 || die "got strange filename '$filename'";
2382 my @lines = split(/\n/, $raw);
2383 foreach my $line (@lines) {
2384 next if $line =~ m/^\s*$/;
2386 if ($line =~ m/^\[PENDING\]\s*$/i) {
2387 $section = 'pending';
2388 if (defined($descr)) {
2390 $conf->{description
} = $descr;
2393 $conf = $res->{$section} = {};
2396 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2398 if (defined($descr)) {
2400 $conf->{description
} = $descr;
2403 $conf = $res->{snapshots
}->{$section} = {};
2407 if ($line =~ m/^\#(.*)\s*$/) {
2408 $descr = '' if !defined($descr);
2409 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2413 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2414 $descr = '' if !defined($descr);
2415 $descr .= PVE
::Tools
::decode_text
($2);
2416 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2417 $conf->{snapstate
} = $1;
2418 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2421 $conf->{$key} = $value;
2422 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2424 if ($section eq 'pending') {
2425 $conf->{delete} = $value; # we parse this later
2427 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2429 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2432 eval { $value = check_type
($key, $value); };
2434 warn "vm $vmid - unable to parse value of '$key' - $@";
2436 $key = 'ide2' if $key eq 'cdrom';
2437 my $fmt = $confdesc->{$key}->{format
};
2438 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2439 my $v = parse_drive
($key, $value);
2440 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2441 $v->{file
} = $volid;
2442 $value = print_drive
($vmid, $v);
2444 warn "vm $vmid - unable to parse value of '$key'\n";
2449 $conf->{$key} = $value;
2454 if (defined($descr)) {
2456 $conf->{description
} = $descr;
2458 delete $res->{snapstate
}; # just to be sure
2463 sub write_vm_config
{
2464 my ($filename, $conf) = @_;
2466 delete $conf->{snapstate
}; # just to be sure
2468 if ($conf->{cdrom
}) {
2469 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2470 $conf->{ide2
} = $conf->{cdrom
};
2471 delete $conf->{cdrom
};
2474 # we do not use 'smp' any longer
2475 if ($conf->{sockets
}) {
2476 delete $conf->{smp
};
2477 } elsif ($conf->{smp
}) {
2478 $conf->{sockets
} = $conf->{smp
};
2479 delete $conf->{cores
};
2480 delete $conf->{smp
};
2483 my $used_volids = {};
2485 my $cleanup_config = sub {
2486 my ($cref, $pending, $snapname) = @_;
2488 foreach my $key (keys %$cref) {
2489 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2490 $key eq 'snapstate' || $key eq 'pending';
2491 my $value = $cref->{$key};
2492 if ($key eq 'delete') {
2493 die "propertry 'delete' is only allowed in [PENDING]\n"
2495 # fixme: check syntax?
2498 eval { $value = check_type
($key, $value); };
2499 die "unable to parse value of '$key' - $@" if $@;
2501 $cref->{$key} = $value;
2503 if (!$snapname && is_valid_drivename
($key)) {
2504 my $drive = parse_drive
($key, $value);
2505 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2510 &$cleanup_config($conf);
2512 &$cleanup_config($conf->{pending
}, 1);
2514 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2515 die "internal error" if $snapname eq 'pending';
2516 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2519 # remove 'unusedX' settings if we re-add a volume
2520 foreach my $key (keys %$conf) {
2521 my $value = $conf->{$key};
2522 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2523 delete $conf->{$key};
2527 my $generate_raw_config = sub {
2528 my ($conf, $pending) = @_;
2532 # add description as comment to top of file
2533 if (defined(my $descr = $conf->{description
})) {
2535 foreach my $cl (split(/\n/, $descr)) {
2536 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2539 $raw .= "#\n" if $pending;
2543 foreach my $key (sort keys %$conf) {
2544 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2545 $raw .= "$key: $conf->{$key}\n";
2550 my $raw = &$generate_raw_config($conf);
2552 if (scalar(keys %{$conf->{pending
}})){
2553 $raw .= "\n[PENDING]\n";
2554 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2557 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2558 $raw .= "\n[$snapname]\n";
2559 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2569 # we use static defaults from our JSON schema configuration
2570 foreach my $key (keys %$confdesc) {
2571 if (defined(my $default = $confdesc->{$key}->{default})) {
2572 $res->{$key} = $default;
2576 my $conf = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
2577 $res->{keyboard
} = $conf->{keyboard
} if $conf->{keyboard
};
2583 my $vmlist = PVE
::Cluster
::get_vmlist
();
2585 return $res if !$vmlist || !$vmlist->{ids
};
2586 my $ids = $vmlist->{ids
};
2588 foreach my $vmid (keys %$ids) {
2589 my $d = $ids->{$vmid};
2590 next if !$d->{node
} || $d->{node
} ne $nodename;
2591 next if !$d->{type
} || $d->{type
} ne 'qemu';
2592 $res->{$vmid}->{exists} = 1;
2597 # test if VM uses local resources (to prevent migration)
2598 sub check_local_resources
{
2599 my ($conf, $noerr) = @_;
2603 $loc_res = 1 if $conf->{hostusb
}; # old syntax
2604 $loc_res = 1 if $conf->{hostpci
}; # old syntax
2606 foreach my $k (keys %$conf) {
2607 next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2608 # sockets are safe: they will recreated be on the target side post-migrate
2609 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2610 $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2613 die "VM uses local resources\n" if $loc_res && !$noerr;
2618 # check if used storages are available on all nodes (use by migrate)
2619 sub check_storage_availability
{
2620 my ($storecfg, $conf, $node) = @_;
2622 foreach_drive
($conf, sub {
2623 my ($ds, $drive) = @_;
2625 my $volid = $drive->{file
};
2628 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2631 # check if storage is available on both nodes
2632 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2633 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2637 # list nodes where all VM images are available (used by has_feature API)
2639 my ($conf, $storecfg) = @_;
2641 my $nodelist = PVE
::Cluster
::get_nodelist
();
2642 my $nodehash = { map { $_ => 1 } @$nodelist };
2643 my $nodename = PVE
::INotify
::nodename
();
2645 foreach_drive
($conf, sub {
2646 my ($ds, $drive) = @_;
2648 my $volid = $drive->{file
};
2651 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2653 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2654 if ($scfg->{disable
}) {
2656 } elsif (my $avail = $scfg->{nodes
}) {
2657 foreach my $node (keys %$nodehash) {
2658 delete $nodehash->{$node} if !$avail->{$node};
2660 } elsif (!$scfg->{shared
}) {
2661 foreach my $node (keys %$nodehash) {
2662 delete $nodehash->{$node} if $node ne $nodename
2672 my ($pidfile, $pid) = @_;
2674 my $fh = IO
::File-
>new("/proc/$pid/cmdline", "r");
2678 return undef if !$line;
2679 my @param = split(/\0/, $line);
2681 my $cmd = $param[0];
2682 return if !$cmd || ($cmd !~ m
|kvm
$| && $cmd !~ m
|qemu-system-x86_64
$|);
2684 for (my $i = 0; $i < scalar (@param); $i++) {
2687 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2688 my $p = $param[$i+1];
2689 return 1 if $p && ($p eq $pidfile);
2698 my ($vmid, $nocheck, $node) = @_;
2700 my $filename = PVE
::QemuConfig-
>config_file($vmid, $node);
2702 die "unable to find configuration file for VM $vmid - no such machine\n"
2703 if !$nocheck && ! -f
$filename;
2705 my $pidfile = pidfile_name
($vmid);
2707 if (my $fd = IO
::File-
>new("<$pidfile")) {
2712 my $mtime = $st->mtime;
2713 if ($mtime > time()) {
2714 warn "file '$filename' modified in future\n";
2717 if ($line =~ m/^(\d+)$/) {
2719 if (check_cmdline
($pidfile, $pid)) {
2720 if (my $pinfo = PVE
::ProcFSTools
::check_process_running
($pid)) {
2732 my $vzlist = config_list
();
2734 my $fd = IO
::Dir-
>new($var_run_tmpdir) || return $vzlist;
2736 while (defined(my $de = $fd->read)) {
2737 next if $de !~ m/^(\d+)\.pid$/;
2739 next if !defined($vzlist->{$vmid});
2740 if (my $pid = check_running
($vmid)) {
2741 $vzlist->{$vmid}->{pid
} = $pid;
2749 my ($storecfg, $conf) = @_;
2751 my $bootdisk = $conf->{bootdisk
};
2752 return undef if !$bootdisk;
2753 return undef if !is_valid_drivename
($bootdisk);
2755 return undef if !$conf->{$bootdisk};
2757 my $drive = parse_drive
($bootdisk, $conf->{$bootdisk});
2758 return undef if !defined($drive);
2760 return undef if drive_is_cdrom
($drive);
2762 my $volid = $drive->{file
};
2763 return undef if !$volid;
2765 return $drive->{size
};
2768 my $last_proc_pid_stat;
2770 # get VM status information
2771 # This must be fast and should not block ($full == false)
2772 # We only query KVM using QMP if $full == true (this can be slow)
2774 my ($opt_vmid, $full) = @_;
2778 my $storecfg = PVE
::Storage
::config
();
2780 my $list = vzlist
();
2781 my $defaults = load_defaults
();
2783 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2785 my $cpucount = $cpuinfo->{cpus
} || 1;
2787 foreach my $vmid (keys %$list) {
2788 next if $opt_vmid && ($vmid ne $opt_vmid);
2790 my $cfspath = PVE
::QemuConfig-
>cfs_config_path($vmid);
2791 my $conf = PVE
::Cluster
::cfs_read_file
($cfspath) || {};
2794 $d->{pid
} = $list->{$vmid}->{pid
};
2796 # fixme: better status?
2797 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
2799 my $size = disksize
($storecfg, $conf);
2800 if (defined($size)) {
2801 $d->{disk
} = 0; # no info available
2802 $d->{maxdisk
} = $size;
2808 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
2809 * ($conf->{cores
} || $defaults->{cores
});
2810 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
2811 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
2813 $d->{name
} = $conf->{name
} || "VM $vmid";
2814 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
2815 : $defaults->{memory
}*(1024*1024);
2817 if ($conf->{balloon
}) {
2818 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
2819 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
2820 : $defaults->{shares
};
2831 $d->{diskwrite
} = 0;
2833 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
2835 $d->{serial
} = 1 if conf_has_serial
($conf);
2840 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
2841 foreach my $dev (keys %$netdev) {
2842 next if $dev !~ m/^tap([1-9]\d*)i/;
2844 my $d = $res->{$vmid};
2847 $d->{netout
} += $netdev->{$dev}->{receive
};
2848 $d->{netin
} += $netdev->{$dev}->{transmit
};
2851 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
2852 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
2857 my $ctime = gettimeofday
;
2859 foreach my $vmid (keys %$list) {
2861 my $d = $res->{$vmid};
2862 my $pid = $d->{pid
};
2865 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
2866 next if !$pstat; # not running
2868 my $used = $pstat->{utime} + $pstat->{stime
};
2870 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
2872 if ($pstat->{vsize
}) {
2873 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
2876 my $old = $last_proc_pid_stat->{$pid};
2878 $last_proc_pid_stat->{$pid} = {
2886 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
2888 if ($dtime > 1000) {
2889 my $dutime = $used - $old->{used
};
2891 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
2892 $last_proc_pid_stat->{$pid} = {
2898 $d->{cpu
} = $old->{cpu
};
2902 return $res if !$full;
2904 my $qmpclient = PVE
::QMPClient-
>new();
2906 my $ballooncb = sub {
2907 my ($vmid, $resp) = @_;
2909 my $info = $resp->{'return'};
2910 return if !$info->{max_mem
};
2912 my $d = $res->{$vmid};
2914 # use memory assigned to VM
2915 $d->{maxmem
} = $info->{max_mem
};
2916 $d->{balloon
} = $info->{actual
};
2918 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
2919 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
2920 $d->{freemem
} = $info->{free_mem
};
2923 $d->{ballooninfo
} = $info;
2926 my $blockstatscb = sub {
2927 my ($vmid, $resp) = @_;
2928 my $data = $resp->{'return'} || [];
2929 my $totalrdbytes = 0;
2930 my $totalwrbytes = 0;
2932 for my $blockstat (@$data) {
2933 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
2934 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
2936 $blockstat->{device
} =~ s/drive-//;
2937 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
2939 $res->{$vmid}->{diskread
} = $totalrdbytes;
2940 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
2943 my $statuscb = sub {
2944 my ($vmid, $resp) = @_;
2946 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
2947 # this fails if ballon driver is not loaded, so this must be
2948 # the last commnand (following command are aborted if this fails).
2949 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
2951 my $status = 'unknown';
2952 if (!defined($status = $resp->{'return'}->{status
})) {
2953 warn "unable to get VM status\n";
2957 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
2960 foreach my $vmid (keys %$list) {
2961 next if $opt_vmid && ($vmid ne $opt_vmid);
2962 next if !$res->{$vmid}->{pid
}; # not running
2963 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
2966 $qmpclient->queue_execute(undef, 2);
2968 foreach my $vmid (keys %$list) {
2969 next if $opt_vmid && ($vmid ne $opt_vmid);
2970 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
2977 my ($conf, $func, @param) = @_;
2979 foreach my $ds (valid_drive_names
()) {
2980 next if !defined($conf->{$ds});
2982 my $drive = parse_drive
($ds, $conf->{$ds});
2985 &$func($ds, $drive, @param);
2990 my ($conf, $func, @param) = @_;
2994 my $test_volid = sub {
2995 my ($volid, $is_cdrom, $replicate, $shared, $snapname) = @_;
2999 $volhash->{$volid}->{cdrom
} //= 1;
3000 $volhash->{$volid}->{cdrom
} = 0 if !$is_cdrom;
3002 $volhash->{$volid}->{replicate
} //= 0;
3003 $volhash->{$volid}->{replicate
} = 1 if $replicate;
3005 $volhash->{$volid}->{shared
} //= 0;
3006 $volhash->{$volid}->{shared
} = 1 if $shared;
3008 $volhash->{$volid}->{referenced_in_config
} //= 0;
3009 $volhash->{$volid}->{referenced_in_config
} = 1 if !defined($snapname);
3011 $volhash->{$volid}->{referenced_in_snapshot
}->{$snapname} = 1
3012 if defined($snapname);
3015 foreach_drive
($conf, sub {
3016 my ($ds, $drive) = @_;
3017 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, undef);
3020 foreach my $snapname (keys %{$conf->{snapshots
}}) {
3021 my $snap = $conf->{snapshots
}->{$snapname};
3022 $test_volid->($snap->{vmstate
}, 0, 1, $snapname);
3023 foreach_drive
($snap, sub {
3024 my ($ds, $drive) = @_;
3025 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, $snapname);
3029 foreach my $volid (keys %$volhash) {
3030 &$func($volid, $volhash->{$volid}, @param);
3034 sub conf_has_serial
{
3037 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3038 if ($conf->{"serial$i"}) {
3046 sub vga_conf_has_spice
{
3049 return 0 if !$vga || $vga !~ m/^qxl([234])?$/;
3054 sub config_to_command
{
3055 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
3058 my $globalFlags = [];
3059 my $machineFlags = [];
3065 my $kvmver = kvm_user_version
();
3066 my $vernum = 0; # unknown
3067 my $ostype = $conf->{ostype
};
3068 my $winversion = windows_version
($ostype);
3069 my $kvm = $conf->{kvm
} // 1;
3071 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n" if (!$cpuinfo->{hvm
} && $kvm);
3073 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
3074 $vernum = $1*1000000+$2*1000;
3075 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
3076 $vernum = $1*1000000+$2*1000+$3;
3079 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
3081 my $have_ovz = -f
'/proc/vz/vestat';
3083 my $q35 = machine_type_is_q35
($conf);
3084 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3085 my $machine_type = $forcemachine || $conf->{machine
};
3086 my $use_old_bios_files = undef;
3087 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3089 my $cpuunits = defined($conf->{cpuunits
}) ?
3090 $conf->{cpuunits
} : $defaults->{cpuunits
};
3092 push @$cmd, '/usr/bin/kvm';
3094 push @$cmd, '-id', $vmid;
3098 my $qmpsocket = qmp_socket
($vmid);
3099 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3100 push @$cmd, '-mon', "chardev=qmp,mode=control";
3103 push @$cmd, '-pidfile' , pidfile_name
($vmid);
3105 push @$cmd, '-daemonize';
3107 if ($conf->{smbios1
}) {
3108 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3111 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3112 die "uefi base image not found\n" if ! -f
$OVMF_CODE;
3116 if (my $efidisk = $conf->{efidisk0
}) {
3117 my $d = PVE
::JSONSchema
::parse_property_string
($efidisk_fmt, $efidisk);
3118 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3119 $format = $d->{format
};
3121 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3122 if (!defined($format)) {
3123 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3124 $format = qemu_img_format
($scfg, $volname);
3128 die "efidisk format must be specified\n"
3129 if !defined($format);
3132 warn "no efidisk configured! Using temporary efivars disk.\n";
3133 $path = "/tmp/$vmid-ovmf.fd";
3134 PVE
::Tools
::file_copy
($OVMF_VARS, $path, -s
$OVMF_VARS);
3138 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$OVMF_CODE";
3139 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
3143 # add usb controllers
3144 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $q35, $usbdesc->{format
}, $MAX_USB_DEVICES);
3145 push @$devices, @usbcontrollers if @usbcontrollers;
3146 my $vga = $conf->{vga
};
3148 my $qxlnum = vga_conf_has_spice
($vga);
3149 $vga = 'qxl' if $qxlnum;
3152 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 9)) {
3153 $vga = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3155 $vga = ($winversion >= 6) ?
'std' : 'cirrus';
3159 # enable absolute mouse coordinates (needed by vnc)
3161 if (defined($conf->{tablet
})) {
3162 $tablet = $conf->{tablet
};
3164 $tablet = $defaults->{tablet
};
3165 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3166 $tablet = 0 if $vga =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3169 push @$devices, '-device', print_tabletdevice_full
($conf) if $tablet;
3172 my $gpu_passthrough;
3175 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3176 my $d = parse_hostpci
($conf->{"hostpci$i"});
3179 my $pcie = $d->{pcie
};
3181 die "q35 machine model is not enabled" if !$q35;
3182 $pciaddr = print_pcie_addr
("hostpci$i");
3184 $pciaddr = print_pci_addr
("hostpci$i", $bridges);
3187 my $rombar = defined($d->{rombar
}) && !$d->{rombar
} ?
',rombar=0' : '';
3188 my $romfile = $d->{romfile
};
3191 if ($d->{'x-vga'}) {
3192 $xvga = ',x-vga=on';
3195 $gpu_passthrough = 1;
3197 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3201 my $pcidevices = $d->{pciid
};
3202 my $multifunction = 1 if @$pcidevices > 1;
3205 foreach my $pcidevice (@$pcidevices) {
3207 my $id = "hostpci$i";
3208 $id .= ".$j" if $multifunction;
3209 my $addr = $pciaddr;
3210 $addr .= ".$j" if $multifunction;
3211 my $devicestr = "vfio-pci,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
3214 $devicestr .= "$rombar$xvga";
3215 $devicestr .= ",multifunction=on" if $multifunction;
3216 $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
3219 push @$devices, '-device', $devicestr;
3225 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES);
3226 push @$devices, @usbdevices if @usbdevices;
3228 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3229 if (my $path = $conf->{"serial$i"}) {
3230 if ($path eq 'socket') {
3231 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3232 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3233 push @$devices, '-device', "isa-serial,chardev=serial$i";
3235 die "no such serial device\n" if ! -c
$path;
3236 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3237 push @$devices, '-device', "isa-serial,chardev=serial$i";
3243 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3244 if (my $path = $conf->{"parallel$i"}) {
3245 die "no such parallel device\n" if ! -c
$path;
3246 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3247 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3248 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3252 my $vmname = $conf->{name
} || "vm$vmid";
3254 push @$cmd, '-name', $vmname;
3257 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3258 $sockets = $conf->{sockets
} if $conf->{sockets
};
3260 my $cores = $conf->{cores
} || 1;
3262 my $maxcpus = $sockets * $cores;
3264 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3266 my $allowed_vcpus = $cpuinfo->{cpus
};
3268 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3269 if ($allowed_vcpus < $maxcpus);
3271 if($hotplug_features->{cpu
} && qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 7)) {
3273 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3274 for (my $i = 2; $i <= $vcpus; $i++) {
3275 my $cpustr = print_cpu_device
($conf,$i);
3276 push @$cmd, '-device', $cpustr;
3281 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3283 push @$cmd, '-nodefaults';
3285 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3287 my $bootindex_hash = {};
3289 foreach my $o (split(//, $bootorder)) {
3290 $bootindex_hash->{$o} = $i*100;
3294 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3296 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3298 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3300 push @$cmd, '-vga', $vga if $vga && $vga !~ m/^serial\d+$/; # for kvm 77 and later
3302 if ($vga && $vga !~ m/^serial\d+$/ && $vga ne 'none'){
3303 my $socket = vnc_socket
($vmid);
3304 push @$cmd, '-vnc', "unix:$socket,x509,password";
3306 push @$cmd, '-nographic';
3310 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3312 my $useLocaltime = $conf->{localtime};
3314 if ($winversion >= 5) { # windows
3315 $useLocaltime = 1 if !defined($conf->{localtime});
3317 # use time drift fix when acpi is enabled
3318 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3319 $tdf = 1 if !defined($conf->{tdf
});
3323 if ($winversion >= 6) {
3324 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3325 push @$cmd, '-no-hpet';
3328 push @$rtcFlags, 'driftfix=slew' if $tdf;
3331 push @$machineFlags, 'accel=tcg';
3334 if ($machine_type) {
3335 push @$machineFlags, "type=${machine_type}";
3338 if ($conf->{startdate
}) {
3339 push @$rtcFlags, "base=$conf->{startdate}";
3340 } elsif ($useLocaltime) {
3341 push @$rtcFlags, 'base=localtime';
3344 my $cpu = $kvm ?
"kvm64" : "qemu64";
3345 if (my $cputype = $conf->{cpu
}) {
3346 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
3347 or die "Cannot parse cpu description: $cputype\n";
3348 $cpu = $cpuconf->{cputype
};
3349 $kvm_off = 1 if $cpuconf->{hidden
};
3351 if (defined(my $flags = $cpuconf->{flags
})) {
3352 push @$cpuFlags, split(";", $flags);
3356 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64';
3358 push @$cpuFlags , '-x2apic'
3359 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3361 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3363 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3365 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3367 push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
3368 push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
3371 add_hyperv_enlightenments
($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios
}, $gpu_passthrough) if $kvm;
3373 push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm;
3375 push @$cpuFlags, 'kvm=off' if $kvm_off;
3377 my $cpu_vendor = $cpu_vendor_list->{$cpu} ||
3378 die "internal error"; # should not happen
3380 push @$cpuFlags, "vendor=${cpu_vendor}"
3381 if $cpu_vendor ne 'default';
3383 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3385 push @$cmd, '-cpu', $cpu;
3387 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3389 push @$cmd, '-S' if $conf->{freeze
};
3391 # set keyboard layout
3392 my $kb = $conf->{keyboard
} || $defaults->{keyboard
};
3393 push @$cmd, '-k', $kb if $kb;
3396 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3397 #push @$cmd, '-soundhw', 'es1370';
3398 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3400 if($conf->{agent
}) {
3401 my $qgasocket = qmp_socket
($vmid, 1);
3402 my $pciaddr = print_pci_addr
("qga0", $bridges);
3403 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3404 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3405 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3413 for(my $i = 1; $i < $qxlnum; $i++){
3414 my $pciaddr = print_pci_addr
("vga$i", $bridges);
3415 push @$cmd, '-device', "qxl,id=vga$i,ram_size=67108864,vram_size=33554432$pciaddr";
3418 # assume other OS works like Linux
3419 push @$cmd, '-global', 'qxl-vga.ram_size=134217728';
3420 push @$cmd, '-global', 'qxl-vga.vram_size=67108864';
3424 my $pciaddr = print_pci_addr
("spice", $bridges);
3426 my $nodename = PVE
::INotify
::nodename
();
3427 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3428 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3429 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3430 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3431 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3433 push @$devices, '-spice', "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3435 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3436 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3437 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3440 # enable balloon by default, unless explicitly disabled
3441 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3442 $pciaddr = print_pci_addr
("balloon0", $bridges);
3443 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3446 if ($conf->{watchdog
}) {
3447 my $wdopts = parse_watchdog
($conf->{watchdog
});
3448 $pciaddr = print_pci_addr
("watchdog", $bridges);
3449 my $watchdog = $wdopts->{model
} || 'i6300esb';
3450 push @$devices, '-device', "$watchdog$pciaddr";
3451 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3455 my $scsicontroller = {};
3456 my $ahcicontroller = {};
3457 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3459 # Add iscsi initiator name if available
3460 if (my $initiator = get_initiator_name
()) {
3461 push @$devices, '-iscsi', "initiator-name=$initiator";
3464 foreach_drive
($conf, sub {
3465 my ($ds, $drive) = @_;
3467 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3468 push @$vollist, $drive->{file
};
3471 # ignore efidisk here, already added in bios/fw handling code above
3472 return if $drive->{interface
} eq 'efidisk';
3474 $use_virtio = 1 if $ds =~ m/^virtio/;
3476 if (drive_is_cdrom
($drive)) {
3477 if ($bootindex_hash->{d
}) {
3478 $drive->{bootindex
} = $bootindex_hash->{d
};
3479 $bootindex_hash->{d
} += 1;
3482 if ($bootindex_hash->{c
}) {
3483 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3484 $bootindex_hash->{c
} += 1;
3488 if($drive->{interface
} eq 'virtio'){
3489 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3492 if ($drive->{interface
} eq 'scsi') {
3494 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3496 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges);
3497 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3500 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3501 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3502 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3503 } elsif ($drive->{iothread
}) {
3504 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3508 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3509 $queues = ",num_queues=$drive->{queues}";
3512 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3513 $scsicontroller->{$controller}=1;
3516 if ($drive->{interface
} eq 'sata') {
3517 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3518 $pciaddr = print_pci_addr
("ahci$controller", $bridges);
3519 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3520 $ahcicontroller->{$controller}=1;
3523 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3524 push @$devices, '-drive',$drive_cmd;
3525 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges);
3528 for (my $i = 0; $i < $MAX_NETS; $i++) {
3529 next if !$conf->{"net$i"};
3530 my $d = parse_net
($conf->{"net$i"});
3533 $use_virtio = 1 if $d->{model
} eq 'virtio';
3535 if ($bootindex_hash->{n
}) {
3536 $d->{bootindex
} = $bootindex_hash->{n
};
3537 $bootindex_hash->{n
} += 1;
3540 my $netdevfull = print_netdev_full
($vmid,$conf,$d,"net$i");
3541 push @$devices, '-netdev', $netdevfull;
3543 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files);
3544 push @$devices, '-device', $netdevicefull;
3549 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3554 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3556 while (my ($k, $v) = each %$bridges) {
3557 $pciaddr = print_pci_addr
("pci.$k");
3558 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3563 if ($conf->{args
}) {
3564 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3568 push @$cmd, @$devices;
3569 push @$cmd, '-rtc', join(',', @$rtcFlags)
3570 if scalar(@$rtcFlags);
3571 push @$cmd, '-machine', join(',', @$machineFlags)
3572 if scalar(@$machineFlags);
3573 push @$cmd, '-global', join(',', @$globalFlags)
3574 if scalar(@$globalFlags);
3576 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3581 return "${var_run_tmpdir}/$vmid.vnc";
3587 my $res = vm_mon_cmd
($vmid, 'query-spice');
3589 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3593 my ($vmid, $qga) = @_;
3594 my $sockettype = $qga ?
'qga' : 'qmp';
3595 return "${var_run_tmpdir}/$vmid.$sockettype";
3600 return "${var_run_tmpdir}/$vmid.pid";
3603 sub vm_devices_list
{
3606 my $res = vm_mon_cmd
($vmid, 'query-pci');
3608 foreach my $pcibus (@$res) {
3609 foreach my $device (@{$pcibus->{devices
}}) {
3610 next if !$device->{'qdev_id'};
3611 if ($device->{'pci_bridge'}) {
3612 $devices->{$device->{'qdev_id'}} = 1;
3613 foreach my $bridge_device (@{$device->{'pci_bridge'}->{devices
}}) {
3614 next if !$bridge_device->{'qdev_id'};
3615 $devices->{$bridge_device->{'qdev_id'}} = 1;
3616 $devices->{$device->{'qdev_id'}}++;
3619 $devices->{$device->{'qdev_id'}} = 1;
3624 my $resblock = vm_mon_cmd
($vmid, 'query-block');
3625 foreach my $block (@$resblock) {
3626 if($block->{device
} =~ m/^drive-(\S+)/){
3631 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
3632 foreach my $mice (@$resmice) {
3633 if ($mice->{name
} eq 'QEMU HID Tablet') {
3634 $devices->{tablet
} = 1;
3639 # for usb devices there is no query-usb
3640 # but we can iterate over the entries in
3641 # qom-list path=/machine/peripheral
3642 my $resperipheral = vm_mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3643 foreach my $per (@$resperipheral) {
3644 if ($per->{name
} =~ m/^usb\d+$/) {
3645 $devices->{$per->{name
}} = 1;
3653 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
3655 my $q35 = machine_type_is_q35
($conf);
3657 my $devices_list = vm_devices_list
($vmid);
3658 return 1 if defined($devices_list->{$deviceid});
3660 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid); # add PCI bridge if we need it for the device
3662 if ($deviceid eq 'tablet') {
3664 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf));
3666 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3668 die "usb hotplug currently not reliable\n";
3669 # since we can't reliably hot unplug all added usb devices
3670 # and usb passthrough disables live migration
3671 # we disable usb hotplugging for now
3672 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
3674 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3676 qemu_iothread_add
($vmid, $deviceid, $device);
3678 qemu_driveadd
($storecfg, $vmid, $device);
3679 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3681 qemu_deviceadd
($vmid, $devicefull);
3682 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3684 eval { qemu_drivedel
($vmid, $deviceid); };
3689 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3692 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
3693 my $pciaddr = print_pci_addr
($deviceid);
3694 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
3696 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
3698 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
3699 qemu_iothread_add
($vmid, $deviceid, $device);
3700 $devicefull .= ",iothread=iothread-$deviceid";
3703 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
3704 $devicefull .= ",num_queues=$device->{queues}";
3707 qemu_deviceadd
($vmid, $devicefull);
3708 qemu_deviceaddverify
($vmid, $deviceid);
3710 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3712 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device);
3713 qemu_driveadd
($storecfg, $vmid, $device);
3715 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3716 eval { qemu_deviceadd
($vmid, $devicefull); };
3718 eval { qemu_drivedel
($vmid, $deviceid); };
3723 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3725 return undef if !qemu_netdevadd
($vmid, $conf, $device, $deviceid);
3727 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
3728 my $use_old_bios_files = undef;
3729 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3731 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files);
3732 qemu_deviceadd
($vmid, $netdevicefull);
3733 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3735 eval { qemu_netdevdel
($vmid, $deviceid); };
3740 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
3743 my $pciaddr = print_pci_addr
($deviceid);
3744 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
3746 qemu_deviceadd
($vmid, $devicefull);
3747 qemu_deviceaddverify
($vmid, $deviceid);
3750 die "can't hotplug device '$deviceid'\n";
3756 # fixme: this should raise exceptions on error!
3757 sub vm_deviceunplug
{
3758 my ($vmid, $conf, $deviceid) = @_;
3760 my $devices_list = vm_devices_list
($vmid);
3761 return 1 if !defined($devices_list->{$deviceid});
3763 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
3765 if ($deviceid eq 'tablet') {
3767 qemu_devicedel
($vmid, $deviceid);
3769 } elsif ($deviceid =~ m/^usb\d+$/) {
3771 die "usb hotplug currently not reliable\n";
3772 # when unplugging usb devices this way,
3773 # there may be remaining usb controllers/hubs
3774 # so we disable it for now
3775 qemu_devicedel
($vmid, $deviceid);
3776 qemu_devicedelverify
($vmid, $deviceid);
3778 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3780 qemu_devicedel
($vmid, $deviceid);
3781 qemu_devicedelverify
($vmid, $deviceid);
3782 qemu_drivedel
($vmid, $deviceid);
3783 qemu_iothread_del
($conf, $vmid, $deviceid);
3785 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3787 qemu_devicedel
($vmid, $deviceid);
3788 qemu_devicedelverify
($vmid, $deviceid);
3789 qemu_iothread_del
($conf, $vmid, $deviceid);
3791 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3793 qemu_devicedel
($vmid, $deviceid);
3794 qemu_drivedel
($vmid, $deviceid);
3795 qemu_deletescsihw
($conf, $vmid, $deviceid);
3797 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3799 qemu_devicedel
($vmid, $deviceid);
3800 qemu_devicedelverify
($vmid, $deviceid);
3801 qemu_netdevdel
($vmid, $deviceid);
3804 die "can't unplug device '$deviceid'\n";
3810 sub qemu_deviceadd
{
3811 my ($vmid, $devicefull) = @_;
3813 $devicefull = "driver=".$devicefull;
3814 my %options = split(/[=,]/, $devicefull);
3816 vm_mon_cmd
($vmid, "device_add" , %options);
3819 sub qemu_devicedel
{
3820 my ($vmid, $deviceid) = @_;
3822 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
3825 sub qemu_iothread_add
{
3826 my($vmid, $deviceid, $device) = @_;
3828 if ($device->{iothread
}) {
3829 my $iothreads = vm_iothreads_list
($vmid);
3830 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
3834 sub qemu_iothread_del
{
3835 my($conf, $vmid, $deviceid) = @_;
3837 my $device = parse_drive
($deviceid, $conf->{$deviceid});
3838 if ($device->{iothread
}) {
3839 my $iothreads = vm_iothreads_list
($vmid);
3840 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
3844 sub qemu_objectadd
{
3845 my($vmid, $objectid, $qomtype) = @_;
3847 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
3852 sub qemu_objectdel
{
3853 my($vmid, $objectid) = @_;
3855 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
3861 my ($storecfg, $vmid, $device) = @_;
3863 my $drive = print_drive_full
($storecfg, $vmid, $device);
3864 $drive =~ s/\\/\\\\/g;
3865 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
3867 # If the command succeeds qemu prints: "OK
"
3868 return 1 if $ret =~ m/OK/s;
3870 die "adding drive failed
: $ret\n";
3874 my($vmid, $deviceid) = @_;
3876 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
3879 return 1 if $ret eq "";
3881 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
3882 return 1 if $ret =~ m/Device \'.*?\' not found/s;
3884 die "deleting drive
$deviceid failed
: $ret\n";
3887 sub qemu_deviceaddverify {
3888 my ($vmid, $deviceid) = @_;
3890 for (my $i = 0; $i <= 5; $i++) {
3891 my $devices_list = vm_devices_list($vmid);
3892 return 1 if defined($devices_list->{$deviceid});
3896 die "error on hotplug device
'$deviceid'\n";
3900 sub qemu_devicedelverify {
3901 my ($vmid, $deviceid) = @_;
3903 # need to verify that the device is correctly removed as device_del
3904 # is async and empty return is not reliable
3906 for (my $i = 0; $i <= 5; $i++) {
3907 my $devices_list = vm_devices_list($vmid);
3908 return 1 if !defined($devices_list->{$deviceid});
3912 die "error on hot-unplugging device
'$deviceid'\n";
3915 sub qemu_findorcreatescsihw {
3916 my ($storecfg, $conf, $vmid, $device) = @_;
3918 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3920 my $scsihwid="$controller_prefix$controller";
3921 my $devices_list = vm_devices_list($vmid);
3923 if(!defined($devices_list->{$scsihwid})) {
3924 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device);
3930 sub qemu_deletescsihw {
3931 my ($conf, $vmid, $opt) = @_;
3933 my $device = parse_drive($opt, $conf->{$opt});
3935 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
3936 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
3940 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3942 my $devices_list = vm_devices_list($vmid);
3943 foreach my $opt (keys %{$devices_list}) {
3944 if (PVE::QemuServer::is_valid_drivename($opt)) {
3945 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
3946 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
3952 my $scsihwid="scsihw
$controller";
3954 vm_deviceunplug($vmid, $conf, $scsihwid);
3959 sub qemu_add_pci_bridge {
3960 my ($storecfg, $conf, $vmid, $device) = @_;
3966 print_pci_addr($device, $bridges);
3968 while (my ($k, $v) = each %$bridges) {
3971 return 1 if !defined($bridgeid) || $bridgeid < 1;
3973 my $bridge = "pci
.$bridgeid";
3974 my $devices_list = vm_devices_list($vmid);
3976 if (!defined($devices_list->{$bridge})) {
3977 vm_deviceplug($storecfg, $conf, $vmid, $bridge);
3983 sub qemu_set_link_status {
3984 my ($vmid, $device, $up) = @_;
3986 vm_mon_cmd($vmid, "set_link
", name => $device,
3987 up => $up ? JSON::true : JSON::false);
3990 sub qemu_netdevadd {
3991 my ($vmid, $conf, $device, $deviceid) = @_;
3993 my $netdev = print_netdev_full($vmid, $conf, $device, $deviceid, 1);
3994 my %options = split(/[=,]/, $netdev);
3996 vm_mon_cmd($vmid, "netdev_add
", %options);
4000 sub qemu_netdevdel {
4001 my ($vmid, $deviceid) = @_;
4003 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
4006 sub qemu_usb_hotplug {
4007 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
4011 # remove the old one first
4012 vm_deviceunplug($vmid, $conf, $deviceid);
4014 # check if xhci controller is necessary and available
4015 if ($device->{usb3}) {
4017 my $devicelist = vm_devices_list($vmid);
4019 if (!$devicelist->{xhci}) {
4020 my $pciaddr = print_pci_addr("xhci
");
4021 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4024 my $d = parse_usb_device($device->{host});
4025 $d->{usb3} = $device->{usb3};
4028 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d);
4031 sub qemu_cpu_hotplug {
4032 my ($vmid, $conf, $vcpus) = @_;
4034 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4037 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4038 $sockets = $conf->{sockets} if $conf->{sockets};
4039 my $cores = $conf->{cores} || 1;
4040 my $maxcpus = $sockets * $cores;
4042 $vcpus = $maxcpus if !$vcpus;
4044 die "you can
't add more vcpus than maxcpus\n"
4045 if $vcpus > $maxcpus;
4047 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4049 if ($vcpus < $currentvcpus) {
4051 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4053 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4054 qemu_devicedel($vmid, "cpu$i");
4056 my $currentrunningvcpus = undef;
4058 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4059 last if scalar(@{$currentrunningvcpus}) == $i-1;
4060 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4064 #update conf after each succesfull cpu unplug
4065 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4066 PVE::QemuConfig->write_config($vmid, $conf);
4069 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4075 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4076 die "vcpus in running vm does not match its configuration\n"
4077 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4079 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4081 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4082 my $cpustr = print_cpu_device($conf, $i);
4083 qemu_deviceadd($vmid, $cpustr);
4086 my $currentrunningvcpus = undef;
4088 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4089 last if scalar(@{$currentrunningvcpus}) == $i;
4090 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4094 #update conf after each succesfull cpu hotplug
4095 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4096 PVE::QemuConfig->write_config($vmid, $conf);
4100 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4101 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4106 sub qemu_block_set_io_throttle {
4107 my ($vmid, $deviceid,
4108 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4109 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4110 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4111 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4113 return if !check_running($vmid) ;
4115 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4117 bps_rd => int($bps_rd),
4118 bps_wr => int($bps_wr),
4120 iops_rd => int($iops_rd),
4121 iops_wr => int($iops_wr),
4122 bps_max => int($bps_max),
4123 bps_rd_max => int($bps_rd_max),
4124 bps_wr_max => int($bps_wr_max),
4125 iops_max => int($iops_max),
4126 iops_rd_max => int($iops_rd_max),
4127 iops_wr_max => int($iops_wr_max),
4128 bps_max_length => int($bps_max_length),
4129 bps_rd_max_length => int($bps_rd_max_length),
4130 bps_wr_max_length => int($bps_wr_max_length),
4131 iops_max_length => int($iops_max_length),
4132 iops_rd_max_length => int($iops_rd_max_length),
4133 iops_wr_max_length => int($iops_wr_max_length),
4138 # old code, only used to shutdown old VM after update
4140 my ($fh, $timeout) = @_;
4142 my $sel = new IO::Select;
4149 while (scalar (@ready = $sel->can_read($timeout))) {
4151 if ($count = $fh->sysread($buf, 8192)) {
4152 if ($buf =~ /^(.*)\(qemu\) $/s) {
4159 if (!defined($count)) {
4166 die "monitor read timeout\n" if !scalar(@ready);
4171 # old code, only used to shutdown old VM after update
4172 sub vm_monitor_command {
4173 my ($vmid, $cmdstr, $nocheck) = @_;
4178 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
4180 my $sname = "${var_run_tmpdir}/$vmid.mon";
4182 my $sock = IO::Socket::UNIX->new( Peer => $sname ) ||
4183 die "unable to connect to VM $vmid socket - $!\n";
4187 # hack: migrate sometime blocks the monitor (when migrate_downtime
4189 if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
4190 $timeout = 60*60; # 1 hour
4194 my $data = __read_avail($sock, $timeout);
4196 if ($data !~ m/^QEMU\s+(\S+)\s+monitor\s/) {
4197 die "got unexpected qemu monitor banner\n";
4200 my $sel = new IO::Select;
4203 if (!scalar(my @ready = $sel->can_write($timeout))) {
4204 die "monitor write error - timeout";
4207 my $fullcmd = "$cmdstr\r";
4209 # syslog('info
', "VM $vmid monitor command: $cmdstr");
4212 if (!($b = $sock->syswrite($fullcmd)) || ($b != length($fullcmd))) {
4213 die "monitor write error - $!";
4216 return if ($cmdstr eq 'q
') || ($cmdstr eq 'quit
');
4220 if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
4221 $timeout = 60*60; # 1 hour
4222 } elsif ($cmdstr =~ m/^(eject|change)/) {
4223 $timeout = 60; # note: cdrom mount command is slow
4225 if ($res = __read_avail($sock, $timeout)) {
4227 my @lines = split("\r?\n", $res);
4229 shift @lines if $lines[0] !~ m/^unknown command/; # skip echo
4231 $res = join("\n", @lines);
4239 syslog("err", "VM $vmid monitor command failed - $err");
4246 sub qemu_block_resize {
4247 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4249 my $running = check_running($vmid);
4251 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4253 return if !$running;
4255 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4259 sub qemu_volume_snapshot {
4260 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4262 my $running = check_running($vmid);
4264 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4265 vm_mon_cmd($vmid, "snapshot-drive", device => $deviceid, name => $snap);
4267 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4271 sub qemu_volume_snapshot_delete {
4272 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4274 my $running = check_running($vmid);
4276 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4277 vm_mon_cmd($vmid, "delete-drive-snapshot", device => $deviceid, name => $snap);
4279 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4283 sub set_migration_caps {
4289 "auto-converge" => 1,
4291 "x-rdma-pin-all" => 0,
4296 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4298 for my $supported_capability (@$supported_capabilities) {
4300 capability => $supported_capability->{capability},
4301 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4305 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4308 my $fast_plug_option = {
4316 'vmstatestorage
' => 1,
4319 # hotplug changes in [PENDING]
4320 # $selection hash can be used to only apply specified options, for
4321 # example: { cores => 1 } (only apply changed 'cores
')
4322 # $errors ref is used to return error messages
4323 sub vmconfig_hotplug_pending {
4324 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4326 my $defaults = load_defaults();
4328 # commit values which do not have any impact on running VM first
4329 # Note: those option cannot raise errors, we we do not care about
4330 # $selection and always apply them.
4332 my $add_error = sub {
4333 my ($opt, $msg) = @_;
4334 $errors->{$opt} = "hotplug problem - $msg";
4338 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4339 if ($fast_plug_option->{$opt}) {
4340 $conf->{$opt} = $conf->{pending}->{$opt};
4341 delete $conf->{pending}->{$opt};
4347 PVE::QemuConfig->write_config($vmid, $conf);
4348 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4351 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4353 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4354 while (my ($opt, $force) = each %$pending_delete_hash) {
4355 next if $selection && !$selection->{$opt};
4357 if ($opt eq 'hotplug
') {
4358 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4359 } elsif ($opt eq 'tablet
') {
4360 die "skip\n" if !$hotplug_features->{usb};
4361 if ($defaults->{tablet}) {
4362 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4364 vm_deviceunplug($vmid, $conf, $opt);
4366 } elsif ($opt =~ m/^usb\d+/) {
4368 # since we cannot reliably hot unplug usb devices
4369 # we are disabling it
4370 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4371 vm_deviceunplug($vmid, $conf, $opt);
4372 } elsif ($opt eq 'vcpus
') {
4373 die "skip\n" if !$hotplug_features->{cpu};
4374 qemu_cpu_hotplug($vmid, $conf, undef);
4375 } elsif ($opt eq 'balloon
') {
4376 # enable balloon device is not hotpluggable
4377 die "skip\n" if !defined($conf->{balloon}) || $conf->{balloon};
4378 } elsif ($fast_plug_option->{$opt}) {
4380 } elsif ($opt =~ m/^net(\d+)$/) {
4381 die "skip\n" if !$hotplug_features->{network};
4382 vm_deviceunplug($vmid, $conf, $opt);
4383 } elsif (is_valid_drivename($opt)) {
4384 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4385 vm_deviceunplug($vmid, $conf, $opt);
4386 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4387 } elsif ($opt =~ m/^memory$/) {
4388 die "skip\n" if !$hotplug_features->{memory};
4389 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4390 } elsif ($opt eq 'cpuunits
') {
4391 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4392 } elsif ($opt eq 'cpulimit
') {
4393 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4399 &$add_error($opt, $err) if $err ne "skip\n";
4401 # save new config if hotplug was successful
4402 delete $conf->{$opt};
4403 vmconfig_undelete_pending_option($conf, $opt);
4404 PVE::QemuConfig->write_config($vmid, $conf);
4405 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4409 my $apply_pending_cloudinit;
4410 $apply_pending_cloudinit = sub {
4411 my ($key, $value) = @_;
4412 $apply_pending_cloudinit = sub {}; # once is enough
4414 my @cloudinit_opts = keys %$confdesc_cloudinit;
4415 foreach my $opt (keys %{$conf->{pending}}) {
4416 next if !grep { $_ eq $opt } @cloudinit_opts;
4417 $conf->{$opt} = delete $conf->{pending}->{$opt};
4420 my $new_conf = { %$conf };
4421 $new_conf->{$key} = $value;
4422 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4425 foreach my $opt (keys %{$conf->{pending}}) {
4426 next if $selection && !$selection->{$opt};
4427 my $value = $conf->{pending}->{$opt};
4429 if ($opt eq 'hotplug
') {
4430 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4431 } elsif ($opt eq 'tablet
') {
4432 die "skip\n" if !$hotplug_features->{usb};
4434 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4435 } elsif ($value == 0) {
4436 vm_deviceunplug($vmid, $conf, $opt);
4438 } elsif ($opt =~ m/^usb\d+$/) {
4440 # since we cannot reliably hot unplug usb devices
4441 # we are disabling it
4442 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4443 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4444 die "skip\n" if !$d;
4445 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d);
4446 } elsif ($opt eq 'vcpus
') {
4447 die "skip\n" if !$hotplug_features->{cpu};
4448 qemu_cpu_hotplug($vmid, $conf, $value);
4449 } elsif ($opt eq 'balloon
') {
4450 # enable/disable balloning device is not hotpluggable
4451 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4452 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4453 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4455 # allow manual ballooning if shares is set to zero
4456 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4457 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4458 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4460 } elsif ($opt =~ m/^net(\d+)$/) {
4461 # some changes can be done without hotplug
4462 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4463 $vmid, $opt, $value);
4464 } elsif (is_valid_drivename($opt)) {
4465 # some changes can be done without hotplug
4466 my $drive = parse_drive($opt, $value);
4467 if (drive_is_cloudinit($drive)) {
4468 &$apply_pending_cloudinit($opt, $value);
4470 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4471 $vmid, $opt, $value, 1);
4472 } elsif ($opt =~ m/^memory$/) { #dimms
4473 die "skip\n" if !$hotplug_features->{memory};
4474 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4475 } elsif ($opt eq 'cpuunits
') {
4476 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4477 } elsif ($opt eq 'cpulimit
') {
4478 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4479 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4481 die "skip\n"; # skip non-hot-pluggable options
4485 &$add_error($opt, $err) if $err ne "skip\n";
4487 # save new config if hotplug was successful
4488 $conf->{$opt} = $value;
4489 delete $conf->{pending}->{$opt};
4490 PVE::QemuConfig->write_config($vmid, $conf);
4491 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4496 sub try_deallocate_drive {
4497 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4499 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4500 my $volid = $drive->{file};
4501 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4502 my $sid = PVE::Storage::parse_volume_id($volid);
4503 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4505 # check if the disk is really unused
4506 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4507 if is_volume_in_use($storecfg, $conf, $key, $volid);
4508 PVE::Storage::vdisk_free($storecfg, $volid);
4511 # If vm is not owner of this disk remove from config
4519 sub vmconfig_delete_or_detach_drive {
4520 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4522 my $drive = parse_drive($opt, $conf->{$opt});
4524 my $rpcenv = PVE::RPCEnvironment::get();
4525 my $authuser = $rpcenv->get_user();
4528 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4529 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4531 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4535 sub vmconfig_apply_pending {
4536 my ($vmid, $conf, $storecfg) = @_;
4540 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4541 while (my ($opt, $force) = each %$pending_delete_hash) {
4542 die "internal error" if $opt =~ m/^unused/;
4543 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4544 if (!defined($conf->{$opt})) {
4545 vmconfig_undelete_pending_option($conf, $opt);
4546 PVE::QemuConfig->write_config($vmid, $conf);
4547 } elsif (is_valid_drivename($opt)) {
4548 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4549 vmconfig_undelete_pending_option($conf, $opt);
4550 delete $conf->{$opt};
4551 PVE::QemuConfig->write_config($vmid, $conf);
4553 vmconfig_undelete_pending_option($conf, $opt);
4554 delete $conf->{$opt};
4555 PVE::QemuConfig->write_config($vmid, $conf);
4559 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4561 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4562 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4564 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4565 # skip if nothing changed
4566 } elsif (is_valid_drivename($opt)) {
4567 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4568 if defined($conf->{$opt});
4569 $conf->{$opt} = $conf->{pending}->{$opt};
4571 $conf->{$opt} = $conf->{pending}->{$opt};
4574 delete $conf->{pending}->{$opt};
4575 PVE::QemuConfig->write_config($vmid, $conf);
4579 my $safe_num_ne = sub {
4582 return 0 if !defined($a) && !defined($b);
4583 return 1 if !defined($a);
4584 return 1 if !defined($b);
4589 my $safe_string_ne = sub {
4592 return 0 if !defined($a) && !defined($b);
4593 return 1 if !defined($a);
4594 return 1 if !defined($b);
4599 sub vmconfig_update_net {
4600 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value) = @_;
4602 my $newnet = parse_net($value);
4604 if ($conf->{$opt}) {
4605 my $oldnet = parse_net($conf->{$opt});
4607 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4608 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4609 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4610 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4612 # for non online change, we try to hot-unplug
4613 die "skip\n" if !$hotplug;
4614 vm_deviceunplug($vmid, $conf, $opt);
4617 die "internal error" if $opt !~ m/net(\d+)/;
4618 my $iface = "tap${vmid}i$1";
4620 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4621 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4622 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4623 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4624 PVE::Network::tap_unplug($iface);
4625 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4626 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4627 # Rate can be applied on its own but any change above needs to
4628 # include the rate in tap_plug since OVS resets everything.
4629 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4632 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4633 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4641 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet);
4647 sub vmconfig_update_disk {
4648 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force) = @_;
4650 # fixme: do we need force?
4652 my $drive = parse_drive($opt, $value);
4654 if ($conf->{$opt}) {
4656 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4658 my $media = $drive->{media} || 'disk
';
4659 my $oldmedia = $old_drive->{media} || 'disk
';
4660 die "unable to change media type\n" if $media ne $oldmedia;
4662 if (!drive_is_cdrom($old_drive)) {
4664 if ($drive->{file} ne $old_drive->{file}) {
4666 die "skip\n" if !$hotplug;
4668 # unplug and register as unused
4669 vm_deviceunplug($vmid, $conf, $opt);
4670 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4673 # update existing disk
4675 # skip non hotpluggable value
4676 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4677 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4678 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4679 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
4684 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4685 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4686 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4687 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4688 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4689 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4690 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4691 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4692 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4693 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4694 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4695 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4696 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4697 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4698 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4699 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4700 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4701 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4703 qemu_block_set_io_throttle($vmid,"drive-$opt",
4704 ($drive->{mbps} || 0)*1024*1024,
4705 ($drive->{mbps_rd} || 0)*1024*1024,
4706 ($drive->{mbps_wr} || 0)*1024*1024,
4707 $drive->{iops} || 0,
4708 $drive->{iops_rd} || 0,
4709 $drive->{iops_wr} || 0,
4710 ($drive->{mbps_max} || 0)*1024*1024,
4711 ($drive->{mbps_rd_max} || 0)*1024*1024,
4712 ($drive->{mbps_wr_max} || 0)*1024*1024,
4713 $drive->{iops_max} || 0,
4714 $drive->{iops_rd_max} || 0,
4715 $drive->{iops_wr_max} || 0,
4716 $drive->{bps_max_length} || 1,
4717 $drive->{bps_rd_max_length} || 1,
4718 $drive->{bps_wr_max_length} || 1,
4719 $drive->{iops_max_length} || 1,
4720 $drive->{iops_rd_max_length} || 1,
4721 $drive->{iops_wr_max_length} || 1);
4730 if ($drive->{file} eq 'none
') {
4731 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
4732 if (drive_is_cloudinit($old_drive)) {
4733 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
4736 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4737 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
4738 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
4746 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4748 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
4749 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive);
4753 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
4754 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
4756 PVE::QemuConfig->lock_config($vmid, sub {
4757 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
4759 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
4761 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4763 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
4765 if (!$statefile && scalar(keys %{$conf->{pending}})) {
4766 vmconfig_apply_pending($vmid, $conf, $storecfg);
4767 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4770 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
4772 my $defaults = load_defaults();
4774 # set environment variable useful inside network script
4775 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
4777 my $local_volumes = {};
4779 if ($targetstorage) {
4780 foreach_drive($conf, sub {
4781 my ($ds, $drive) = @_;
4783 return if drive_is_cdrom($drive);
4785 my $volid = $drive->{file};
4789 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
4791 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4792 return if $scfg->{shared};
4793 $local_volumes->{$ds} = [$volid, $storeid, $volname];
4798 foreach my $opt (sort keys %$local_volumes) {
4800 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
4801 my $drive = parse_drive($opt, $conf->{$opt});
4803 #if remote storage is specified, use default format
4804 if ($targetstorage && $targetstorage ne "1") {
4805 $storeid = $targetstorage;
4806 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
4807 $format = $defFormat;
4809 #else we use same format than original
4810 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4811 $format = qemu_img_format($scfg, $volid);
4814 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
4815 my $newdrive = $drive;
4816 $newdrive->{format} = $format;
4817 $newdrive->{file} = $newvolid;
4818 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
4819 $local_volumes->{$opt} = $drivestr;
4820 #pass drive to conf for command line
4821 $conf->{$opt} = $drivestr;
4825 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
4827 my $migrate_port = 0;
4830 if ($statefile eq 'tcp
') {
4831 my $localip = "localhost";
4832 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
4833 my $nodename = PVE::INotify::nodename();
4835 if (!defined($migration_type)) {
4836 if (defined($datacenterconf->{migration}->{type})) {
4837 $migration_type = $datacenterconf->{migration}->{type};
4839 $migration_type = 'secure
';
4843 if ($migration_type eq 'insecure
') {
4844 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
4845 if ($migrate_network_addr) {
4846 $localip = $migrate_network_addr;
4848 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
4851 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4854 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4855 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4856 $migrate_uri = "tcp:${localip}:${migrate_port}";
4857 push @$cmd, '-incoming
', $migrate_uri;
4860 } elsif ($statefile eq 'unix
') {
4861 # should be default for secure migrations as a ssh TCP forward
4862 # tunnel is not deterministic reliable ready and fails regurarly
4863 # to set up in time, so use UNIX socket forwards
4864 my $socket_addr = "/run/qemu-server/$vmid.migrate";
4865 unlink $socket_addr;
4867 $migrate_uri = "unix:$socket_addr";
4869 push @$cmd, '-incoming
', $migrate_uri;
4873 push @$cmd, '-loadstate
', $statefile;
4880 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
4881 my $d = parse_hostpci($conf->{"hostpci$i"});
4883 my $pcidevices = $d->{pciid};
4884 foreach my $pcidevice (@$pcidevices) {
4885 my $pciid = $pcidevice->{id}.".".$pcidevice->{function};
4887 my $info = pci_device_info("0000:$pciid");
4888 die "IOMMU not present\n" if !check_iommu_support();
4889 die "no pci device info for device '$pciid'\n" if !$info;
4890 die "can't unbind
/bind pci group to vfio
'$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
4891 die "can
't reset pci device '$pciid'\n" if $info->{has_fl_reset} and !pci_dev_reset($info);
4895 PVE::Storage::activate_volumes($storecfg, $vollist);
4897 if (!check_running($vmid, 1)) {
4899 run_command(['/bin/systemctl
', 'stop
', "$vmid.scope"],
4900 outfunc => sub {}, errfunc => sub {});
4904 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
4905 : $defaults->{cpuunits};
4907 my $start_timeout = $conf->{hugepages} ? 300 : 30;
4908 my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
4911 Slice => 'qemu
.slice
',
4913 CPUShares => $cpuunits
4916 if (my $cpulimit = $conf->{cpulimit}) {
4917 $properties{CPUQuota} = int($cpulimit * 100);
4919 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
4921 if ($conf->{hugepages}) {
4924 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
4925 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
4927 PVE::QemuServer::Memory::hugepages_mount();
4928 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
4931 PVE::Tools::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4932 run_command($cmd, %run_params);
4936 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
4940 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
4942 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
4946 PVE::Tools::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4947 run_command($cmd, %run_params);
4952 # deactivate volumes if start fails
4953 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
4954 die "start failed: $err";
4957 print "migration listens on $migrate_uri\n" if $migrate_uri;
4959 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
4960 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
4964 #start nbd server for storage migration
4965 if ($targetstorage) {
4966 my $nodename = PVE::INotify::nodename();
4967 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
4968 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
4969 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4970 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4972 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${migrate_port}" } } );
4974 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4976 foreach my $opt (sort keys %$local_volumes) {
4977 my $volid = $local_volumes->{$opt};
4978 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
4979 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
4980 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
4984 if ($migratedfrom) {
4986 set_migration_caps($vmid);
4991 print "spice listens on port $spice_port\n";
4992 if ($spice_ticket) {
4993 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
4994 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
4999 if (!$statefile && (!defined($conf->{balloon}) || $conf->{balloon})) {
5000 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5001 if $conf->{balloon};
5004 foreach my $opt (keys %$conf) {
5005 next if $opt !~ m/^net\d+$/;
5006 my $nicconf = parse_net($conf->{$opt});
5007 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
5011 vm_mon_cmd_nocheck($vmid, 'qom-set
',
5012 path => "machine/peripheral/balloon0",
5013 property => "guest-stats-polling-interval",
5014 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
5020 my ($vmid, $execute, %params) = @_;
5022 my $cmd = { execute => $execute, arguments => \%params };
5023 vm_qmp_command($vmid, $cmd);
5026 sub vm_mon_cmd_nocheck {
5027 my ($vmid, $execute, %params) = @_;
5029 my $cmd = { execute => $execute, arguments => \%params };
5030 vm_qmp_command($vmid, $cmd, 1);
5033 sub vm_qmp_command {
5034 my ($vmid, $cmd, $nocheck) = @_;
5039 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
5040 $timeout = $cmd->{arguments}->{timeout};
5041 delete $cmd->{arguments}->{timeout};
5045 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
5046 my $sname = qmp_socket($vmid);
5047 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
5048 my $qmpclient = PVE::QMPClient->new();
5050 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
5051 } elsif (-e "${var_run_tmpdir}/$vmid.mon") {
5052 die "can't execute complex command on old monitor
- stop
/start your vm to fix the problem
\n"
5053 if scalar(%{$cmd->{arguments}});
5054 vm_monitor_command($vmid, $cmd->{execute}, $nocheck);
5056 die "unable to
open monitor
socket\n";
5060 syslog("err
", "VM
$vmid qmp command failed
- $err");
5067 sub vm_human_monitor_command {
5068 my ($vmid, $cmdline) = @_;
5073 execute => 'human-monitor-command',
5074 arguments => { 'command-line' => $cmdline},
5077 return vm_qmp_command($vmid, $cmd);
5080 sub vm_commandline {
5081 my ($storecfg, $vmid) = @_;
5083 my $conf = PVE::QemuConfig->load_config($vmid);
5085 my $defaults = load_defaults();
5087 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
5089 return PVE::Tools::cmd2string($cmd);
5093 my ($vmid, $skiplock) = @_;
5095 PVE::QemuConfig->lock_config($vmid, sub {
5097 my $conf = PVE::QemuConfig->load_config($vmid);
5099 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5101 vm_mon_cmd($vmid, "system_reset
");
5105 sub get_vm_volumes {
5109 foreach_volid($conf, sub {
5110 my ($volid, $attr) = @_;
5112 return if $volid =~ m|^/|;
5114 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5117 push @$vollist, $volid;
5123 sub vm_stop_cleanup {
5124 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5129 my $vollist = get_vm_volumes($conf);
5130 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5133 foreach my $ext (qw(mon qmp pid vnc qga)) {
5134 unlink "/var/run/qemu-server/${vmid}.$ext";
5137 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5139 warn $@ if $@; # avoid errors - just warn
5142 # Note: use $nockeck to skip tests if VM configuration file exists.
5143 # We need that when migration VMs to other nodes (files already moved)
5144 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5146 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5148 $force = 1 if !defined($force) && !$shutdown;
5151 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5152 kill 15, $pid if $pid;
5153 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5154 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5158 PVE
::QemuConfig-
>lock_config($vmid, sub {
5160 my $pid = check_running
($vmid, $nocheck);
5165 $conf = PVE
::QemuConfig-
>load_config($vmid);
5166 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5167 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5168 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5169 $timeout = $opts->{down
} if $opts->{down
};
5173 $timeout = 60 if !defined($timeout);
5177 if (defined($conf) && $conf->{agent
}) {
5178 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
5180 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
5183 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
5190 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5195 if ($count >= $timeout) {
5197 warn "VM still running - terminating now with SIGTERM\n";
5200 die "VM quit/powerdown failed - got timeout\n";
5203 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5208 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5211 die "VM quit/powerdown failed\n";
5219 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5224 if ($count >= $timeout) {
5225 warn "VM still running - terminating now with SIGKILL\n";
5230 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5235 my ($vmid, $skiplock) = @_;
5237 PVE
::QemuConfig-
>lock_config($vmid, sub {
5239 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5241 PVE
::QemuConfig-
>check_lock($conf)
5242 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5244 vm_mon_cmd
($vmid, "stop");
5249 my ($vmid, $skiplock, $nocheck) = @_;
5251 PVE
::QemuConfig-
>lock_config($vmid, sub {
5255 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5257 PVE
::QemuConfig-
>check_lock($conf)
5258 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5260 vm_mon_cmd
($vmid, "cont");
5263 vm_mon_cmd_nocheck
($vmid, "cont");
5269 my ($vmid, $skiplock, $key) = @_;
5271 PVE
::QemuConfig-
>lock_config($vmid, sub {
5273 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5275 # there is no qmp command, so we use the human monitor command
5276 vm_human_monitor_command
($vmid, "sendkey $key");
5281 my ($storecfg, $vmid, $skiplock) = @_;
5283 PVE
::QemuConfig-
>lock_config($vmid, sub {
5285 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5287 if (!check_running
($vmid)) {
5288 destroy_vm
($storecfg, $vmid, undef, $skiplock);
5290 die "VM $vmid is running - destroy failed\n";
5298 my ($filename, $buf) = @_;
5300 my $fh = IO
::File-
>new($filename, "w");
5301 return undef if !$fh;
5303 my $res = print $fh $buf;
5310 sub pci_device_info
{
5315 return undef if $name !~ m/^([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\.([a-f0-9])$/;
5316 my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4);
5318 my $irq = file_read_firstline
("$pcisysfs/devices/$name/irq");
5319 return undef if !defined($irq) || $irq !~ m/^\d+$/;
5321 my $vendor = file_read_firstline
("$pcisysfs/devices/$name/vendor");
5322 return undef if !defined($vendor) || $vendor !~ s/^0x//;
5324 my $product = file_read_firstline
("$pcisysfs/devices/$name/device");
5325 return undef if !defined($product) || $product !~ s/^0x//;
5330 product
=> $product,
5336 has_fl_reset
=> -f
"$pcisysfs/devices/$name/reset" || 0,
5345 my $name = $dev->{name
};
5347 my $fn = "$pcisysfs/devices/$name/reset";
5349 return file_write
($fn, "1");
5352 sub pci_dev_bind_to_vfio
{
5355 my $name = $dev->{name
};
5357 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5359 if (!-d
$vfio_basedir) {
5360 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5362 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5364 my $testdir = "$vfio_basedir/$name";
5365 return 1 if -d
$testdir;
5367 my $data = "$dev->{vendor} $dev->{product}";
5368 return undef if !file_write
("$vfio_basedir/new_id", $data);
5370 my $fn = "$pcisysfs/devices/$name/driver/unbind";
5371 if (!file_write
($fn, $name)) {
5372 return undef if -f
$fn;
5375 $fn = "$vfio_basedir/bind";
5376 if (! -d
$testdir) {
5377 return undef if !file_write
($fn, $name);
5383 sub pci_dev_group_bind_to_vfio
{
5386 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5388 if (!-d
$vfio_basedir) {
5389 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5391 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5393 # get IOMMU group devices
5394 opendir(my $D, "$pcisysfs/devices/0000:$pciid/iommu_group/devices/") || die "Cannot open iommu_group: $!\n";
5395 my @devs = grep /^0000:/, readdir($D);
5398 foreach my $pciid (@devs) {
5399 $pciid =~ m/^([:\.\da-f]+)$/ or die "PCI ID $pciid not valid!\n";
5401 # pci bridges, switches or root ports are not supported
5402 # they have a pci_bus subdirectory so skip them
5403 next if (-e
"$pcisysfs/devices/$pciid/pci_bus");
5405 my $info = pci_device_info
($1);
5406 pci_dev_bind_to_vfio
($info) || die "Cannot bind $pciid to vfio\n";
5412 # vzdump restore implementaion
5414 sub tar_archive_read_firstfile
{
5415 my $archive = shift;
5417 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5419 # try to detect archive type first
5420 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5421 die "unable to open file '$archive'\n";
5422 my $firstfile = <$fh>;
5426 die "ERROR: archive contaions no data\n" if !$firstfile;
5432 sub tar_restore_cleanup
{
5433 my ($storecfg, $statfile) = @_;
5435 print STDERR
"starting cleanup\n";
5437 if (my $fd = IO
::File-
>new($statfile, "r")) {
5438 while (defined(my $line = <$fd>)) {
5439 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5442 if ($volid =~ m
|^/|) {
5443 unlink $volid || die 'unlink failed\n';
5445 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5447 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5449 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5451 print STDERR
"unable to parse line in statfile - $line";
5458 sub restore_archive
{
5459 my ($archive, $vmid, $user, $opts) = @_;
5461 my $format = $opts->{format
};
5464 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5465 $format = 'tar' if !$format;
5467 } elsif ($archive =~ m/\.tar$/) {
5468 $format = 'tar' if !$format;
5469 } elsif ($archive =~ m/.tar.lzo$/) {
5470 $format = 'tar' if !$format;
5472 } elsif ($archive =~ m/\.vma$/) {
5473 $format = 'vma' if !$format;
5474 } elsif ($archive =~ m/\.vma\.gz$/) {
5475 $format = 'vma' if !$format;
5477 } elsif ($archive =~ m/\.vma\.lzo$/) {
5478 $format = 'vma' if !$format;
5481 $format = 'vma' if !$format; # default
5484 # try to detect archive format
5485 if ($format eq 'tar') {
5486 return restore_tar_archive
($archive, $vmid, $user, $opts);
5488 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5492 sub restore_update_config_line
{
5493 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5495 return if $line =~ m/^\#qmdump\#/;
5496 return if $line =~ m/^\#vzdump\#/;
5497 return if $line =~ m/^lock:/;
5498 return if $line =~ m/^unused\d+:/;
5499 return if $line =~ m/^parent:/;
5500 return if $line =~ m/^template:/; # restored VM is never a template
5502 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5503 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5504 # try to convert old 1.X settings
5505 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5506 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5507 my ($model, $macaddr) = split(/\=/, $devconfig);
5508 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5511 bridge
=> "vmbr$ind",
5512 macaddr
=> $macaddr,
5514 my $netstr = print_net
($net);
5516 print $outfd "net$cookie->{netcount}: $netstr\n";
5517 $cookie->{netcount
}++;
5519 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5520 my ($id, $netstr) = ($1, $2);
5521 my $net = parse_net
($netstr);
5522 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5523 $netstr = print_net
($net);
5524 print $outfd "$id: $netstr\n";
5525 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5528 my $di = parse_drive
($virtdev, $value);
5529 if (defined($di->{backup
}) && !$di->{backup
}) {
5530 print $outfd "#$line";
5531 } elsif ($map->{$virtdev}) {
5532 delete $di->{format
}; # format can change on restore
5533 $di->{file
} = $map->{$virtdev};
5534 $value = print_drive
($vmid, $di);
5535 print $outfd "$virtdev: $value\n";
5539 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5540 my ($uuid, $uuid_str);
5541 UUID
::generate
($uuid);
5542 UUID
::unparse
($uuid, $uuid_str);
5543 my $smbios1 = parse_smbios1
($2);
5544 $smbios1->{uuid
} = $uuid_str;
5545 print $outfd $1.print_smbios1
($smbios1)."\n";
5552 my ($cfg, $vmid) = @_;
5554 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5556 my $volid_hash = {};
5557 foreach my $storeid (keys %$info) {
5558 foreach my $item (@{$info->{$storeid}}) {
5559 next if !($item->{volid
} && $item->{size
});
5560 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5561 $volid_hash->{$item->{volid
}} = $item;
5568 sub is_volume_in_use
{
5569 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5571 my $path = PVE
::Storage
::path
($storecfg, $volid);
5573 my $scan_config = sub {
5574 my ($cref, $snapname) = @_;
5576 foreach my $key (keys %$cref) {
5577 my $value = $cref->{$key};
5578 if (is_valid_drivename
($key)) {
5579 next if $skip_drive && $key eq $skip_drive;
5580 my $drive = parse_drive
($key, $value);
5581 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5582 return 1 if $volid eq $drive->{file
};
5583 if ($drive->{file
} =~ m!^/!) {
5584 return 1 if $drive->{file
} eq $path;
5586 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5588 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5590 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5598 return 1 if &$scan_config($conf);
5602 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5603 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5609 sub update_disksize
{
5610 my ($vmid, $conf, $volid_hash) = @_;
5614 # used and unused disks
5615 my $referenced = {};
5617 # Note: it is allowed to define multiple storages with same path (alias), so
5618 # we need to check both 'volid' and real 'path' (two different volid can point
5619 # to the same path).
5621 my $referencedpath = {};
5624 foreach my $opt (keys %$conf) {
5625 if (is_valid_drivename
($opt)) {
5626 my $drive = parse_drive
($opt, $conf->{$opt});
5627 my $volid = $drive->{file
};
5630 $referenced->{$volid} = 1;
5631 if ($volid_hash->{$volid} &&
5632 (my $path = $volid_hash->{$volid}->{path
})) {
5633 $referencedpath->{$path} = 1;
5636 next if drive_is_cdrom
($drive);
5637 next if !$volid_hash->{$volid};
5639 $drive->{size
} = $volid_hash->{$volid}->{size
};
5640 my $new = print_drive
($vmid, $drive);
5641 if ($new ne $conf->{$opt}) {
5643 $conf->{$opt} = $new;
5648 # remove 'unusedX' entry if volume is used
5649 foreach my $opt (keys %$conf) {
5650 next if $opt !~ m/^unused\d+$/;
5651 my $volid = $conf->{$opt};
5652 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5653 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5655 delete $conf->{$opt};
5658 $referenced->{$volid} = 1;
5659 $referencedpath->{$path} = 1 if $path;
5662 foreach my $volid (sort keys %$volid_hash) {
5663 next if $volid =~ m/vm-$vmid-state-/;
5664 next if $referenced->{$volid};
5665 my $path = $volid_hash->{$volid}->{path
};
5666 next if !$path; # just to be sure
5667 next if $referencedpath->{$path};
5669 PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5670 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
5677 my ($vmid, $nolock) = @_;
5679 my $cfg = PVE
::Storage
::config
();
5681 my $volid_hash = scan_volids
($cfg, $vmid);
5683 my $updatefn = sub {
5686 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5688 PVE
::QemuConfig-
>check_lock($conf);
5691 foreach my $volid (keys %$volid_hash) {
5692 my $info = $volid_hash->{$volid};
5693 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5696 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5698 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes;
5701 if (defined($vmid)) {
5705 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5708 my $vmlist = config_list
();
5709 foreach my $vmid (keys %$vmlist) {
5713 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5719 sub restore_vma_archive
{
5720 my ($archive, $vmid, $user, $opts, $comp) = @_;
5722 my $input = $archive eq '-' ?
"<&STDIN" : undef;
5723 my $readfrom = $archive;
5728 my $qarchive = PVE
::Tools
::shellquote
($archive);
5729 if ($comp eq 'gzip') {
5730 $uncomp = "zcat $qarchive|";
5731 } elsif ($comp eq 'lzop') {
5732 $uncomp = "lzop -d -c $qarchive|";
5734 die "unknown compression method '$comp'\n";
5739 my $tmpdir = "/var/tmp/vzdumptmp$$";
5742 # disable interrupts (always do cleanups)
5746 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
5748 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
5749 POSIX
::mkfifo
($mapfifo, 0600);
5752 my $openfifo = sub {
5753 open($fifofh, '>', $mapfifo) || die $!;
5756 my $cmd = "${uncomp}vma extract -v -r $mapfifo $readfrom $tmpdir";
5763 my $rpcenv = PVE
::RPCEnvironment
::get
();
5765 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5766 my $tmpfn = "$conffile.$$.tmp";
5768 # Note: $oldconf is undef if VM does not exists
5769 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
5770 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
5772 my $print_devmap = sub {
5773 my $virtdev_hash = {};
5775 my $cfgfn = "$tmpdir/qemu-server.conf";
5777 # we can read the config - that is already extracted
5778 my $fh = IO
::File-
>new($cfgfn, "r") ||
5779 "unable to read qemu-server.conf - $!\n";
5781 my $fwcfgfn = "$tmpdir/qemu-server.fw";
5783 my $pve_firewall_dir = '/etc/pve/firewall';
5784 mkdir $pve_firewall_dir; # make sure the dir exists
5785 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
5788 while (defined(my $line = <$fh>)) {
5789 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
5790 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
5791 die "archive does not contain data for drive '$virtdev'\n"
5792 if !$devinfo->{$devname};
5793 if (defined($opts->{storage
})) {
5794 $storeid = $opts->{storage
} || 'local';
5795 } elsif (!$storeid) {
5798 $format = 'raw' if !$format;
5799 $devinfo->{$devname}->{devname
} = $devname;
5800 $devinfo->{$devname}->{virtdev
} = $virtdev;
5801 $devinfo->{$devname}->{format
} = $format;
5802 $devinfo->{$devname}->{storeid
} = $storeid;
5804 # check permission on storage
5805 my $pool = $opts->{pool
}; # todo: do we need that?
5806 if ($user ne 'root@pam') {
5807 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
5810 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
5814 foreach my $devname (keys %$devinfo) {
5815 die "found no device mapping information for device '$devname'\n"
5816 if !$devinfo->{$devname}->{virtdev
};
5819 my $cfg = PVE
::Storage
::config
();
5821 # create empty/temp config
5823 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
5824 foreach_drive
($oldconf, sub {
5825 my ($ds, $drive) = @_;
5827 return if drive_is_cdrom
($drive);
5829 my $volid = $drive->{file
};
5831 return if !$volid || $volid =~ m
|^/|;
5833 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
5834 return if !$path || !$owner || ($owner != $vmid);
5836 # Note: only delete disk we want to restore
5837 # other volumes will become unused
5838 if ($virtdev_hash->{$ds}) {
5839 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
5846 # delete vmstate files
5847 # since after the restore we have no snapshots anymore
5848 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
5849 my $snap = $oldconf->{snapshots
}->{$snapname};
5850 if ($snap->{vmstate
}) {
5851 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
5860 foreach my $virtdev (sort keys %$virtdev_hash) {
5861 my $d = $virtdev_hash->{$virtdev};
5862 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
5863 my $scfg = PVE
::Storage
::storage_config
($cfg, $d->{storeid
});
5865 # test if requested format is supported
5866 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $d->{storeid
});
5867 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
5868 $d->{format
} = $defFormat if !$supported;
5870 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $d->{storeid
}, $vmid,
5871 $d->{format
}, undef, $alloc_size);
5872 print STDERR
"new volume ID is '$volid'\n";
5873 $d->{volid
} = $volid;
5874 my $path = PVE
::Storage
::path
($cfg, $volid);
5876 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
5878 my $write_zeros = 1;
5879 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
5883 print $fifofh "format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
5885 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
5886 $map->{$virtdev} = $volid;
5889 $fh->seek(0, 0) || die "seek failed - $!\n";
5891 my $outfd = new IO
::File
($tmpfn, "w") ||
5892 die "unable to write config for VM $vmid\n";
5894 my $cookie = { netcount
=> 0 };
5895 while (defined(my $line = <$fh>)) {
5896 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
5909 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
5910 local $SIG{ALRM
} = sub { die "got timeout\n"; };
5912 $oldtimeout = alarm($timeout);
5919 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
5920 my ($dev_id, $size, $devname) = ($1, $2, $3);
5921 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
5922 } elsif ($line =~ m/^CTIME: /) {
5923 # we correctly received the vma config, so we can disable
5924 # the timeout now for disk allocation (set to 10 minutes, so
5925 # that we always timeout if something goes wrong)
5928 print $fifofh "done\n";
5929 my $tmp = $oldtimeout || 0;
5930 $oldtimeout = undef;
5936 print "restore vma archive: $cmd\n";
5937 run_command
($cmd, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
5941 alarm($oldtimeout) if $oldtimeout;
5944 foreach my $devname (keys %$devinfo) {
5945 my $volid = $devinfo->{$devname}->{volid
};
5946 push @$vollist, $volid if $volid;
5949 my $cfg = PVE
::Storage
::config
();
5950 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
5958 foreach my $devname (keys %$devinfo) {
5959 my $volid = $devinfo->{$devname}->{volid
};
5962 if ($volid =~ m
|^/|) {
5963 unlink $volid || die 'unlink failed\n';
5965 PVE
::Storage
::vdisk_free
($cfg, $volid);
5967 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5969 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5976 rename($tmpfn, $conffile) ||
5977 die "unable to commit configuration file '$conffile'\n";
5979 PVE
::Cluster
::cfs_update
(); # make sure we read new file
5981 eval { rescan
($vmid, 1); };
5985 sub restore_tar_archive
{
5986 my ($archive, $vmid, $user, $opts) = @_;
5988 if ($archive ne '-') {
5989 my $firstfile = tar_archive_read_firstfile
($archive);
5990 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
5991 if $firstfile ne 'qemu-server.conf';
5994 my $storecfg = PVE
::Storage
::config
();
5996 # destroy existing data - keep empty config
5997 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
5998 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
6000 my $tocmd = "/usr/lib/qemu-server/qmextract";
6002 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
6003 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
6004 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6005 $tocmd .= ' --info' if $opts->{info
};
6007 # tar option "xf" does not autodetect compression when read from STDIN,
6008 # so we pipe to zcat
6009 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6010 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6012 my $tmpdir = "/var/tmp/vzdumptmp$$";
6015 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6016 local $ENV{VZDUMP_VMID
} = $vmid;
6017 local $ENV{VZDUMP_USER
} = $user;
6019 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6020 my $tmpfn = "$conffile.$$.tmp";
6022 # disable interrupts (always do cleanups)
6026 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6034 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6036 if ($archive eq '-') {
6037 print "extracting archive from STDIN\n";
6038 run_command
($cmd, input
=> "<&STDIN");
6040 print "extracting archive '$archive'\n";
6044 return if $opts->{info
};
6048 my $statfile = "$tmpdir/qmrestore.stat";
6049 if (my $fd = IO
::File-
>new($statfile, "r")) {
6050 while (defined (my $line = <$fd>)) {
6051 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6052 $map->{$1} = $2 if $1;
6054 print STDERR
"unable to parse line in statfile - $line\n";
6060 my $confsrc = "$tmpdir/qemu-server.conf";
6062 my $srcfd = new IO
::File
($confsrc, "r") ||
6063 die "unable to open file '$confsrc'\n";
6065 my $outfd = new IO
::File
($tmpfn, "w") ||
6066 die "unable to write config for VM $vmid\n";
6068 my $cookie = { netcount
=> 0 };
6069 while (defined (my $line = <$srcfd>)) {
6070 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6082 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6089 rename $tmpfn, $conffile ||
6090 die "unable to commit configuration file '$conffile'\n";
6092 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6094 eval { rescan
($vmid, 1); };
6098 sub foreach_storage_used_by_vm
{
6099 my ($conf, $func) = @_;
6103 foreach_drive
($conf, sub {
6104 my ($ds, $drive) = @_;
6105 return if drive_is_cdrom
($drive);
6107 my $volid = $drive->{file
};
6109 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6110 $sidhash->{$sid} = $sid if $sid;
6113 foreach my $sid (sort keys %$sidhash) {
6118 sub do_snapshots_with_qemu
{
6119 my ($storecfg, $volid) = @_;
6121 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6123 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
6124 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
6128 if ($volid =~ m/\.(qcow2|qed)$/){
6135 sub qga_check_running
{
6138 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6140 warn "Qemu Guest Agent is not running - $@";
6146 sub template_create
{
6147 my ($vmid, $conf, $disk) = @_;
6149 my $storecfg = PVE
::Storage
::config
();
6151 foreach_drive
($conf, sub {
6152 my ($ds, $drive) = @_;
6154 return if drive_is_cdrom
($drive);
6155 return if $disk && $ds ne $disk;
6157 my $volid = $drive->{file
};
6158 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6160 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6161 $drive->{file
} = $voliddst;
6162 $conf->{$ds} = print_drive
($vmid, $drive);
6163 PVE
::QemuConfig-
>write_config($vmid, $conf);
6167 sub qemu_img_convert
{
6168 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6170 my $storecfg = PVE
::Storage
::config
();
6171 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6172 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6174 if ($src_storeid && $dst_storeid) {
6176 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6178 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6179 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6181 my $src_format = qemu_img_format
($src_scfg, $src_volname);
6182 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6184 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6185 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6188 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6189 push @$cmd, '-s', $snapname if($snapname && $src_format eq "qcow2");
6190 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
6191 if ($is_zero_initialized) {
6192 push @$cmd, "zeroinit:$dst_path";
6194 push @$cmd, $dst_path;
6199 if($line =~ m/\((\S+)\/100\
%\)/){
6201 my $transferred = int($size * $percent / 100);
6202 my $remaining = $size - $transferred;
6204 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6209 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6211 die "copy failed: $err" if $err;
6215 sub qemu_img_format
{
6216 my ($scfg, $volname) = @_;
6218 if ($scfg->{path
} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
6225 sub qemu_drive_mirror
{
6226 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga) = @_;
6228 $jobs = {} if !$jobs;
6232 $jobs->{"drive-$drive"} = {};
6234 if ($dst_volid =~ /^nbd:/) {
6235 $qemu_target = $dst_volid;
6238 my $storecfg = PVE
::Storage
::config
();
6239 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6241 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6243 $format = qemu_img_format
($dst_scfg, $dst_volname);
6245 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6247 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6250 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6251 $opts->{format
} = $format if $format;
6253 print "drive mirror is starting for drive-$drive\n";
6255 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
6258 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6259 die "mirroring error: $err";
6262 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
6265 sub qemu_drive_mirror_monitor
{
6266 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
6269 my $err_complete = 0;
6272 die "storage migration timed out\n" if $err_complete > 300;
6274 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6276 my $running_mirror_jobs = {};
6277 foreach my $stat (@$stats) {
6278 next if $stat->{type
} ne 'mirror';
6279 $running_mirror_jobs->{$stat->{device
}} = $stat;
6282 my $readycounter = 0;
6284 foreach my $job (keys %$jobs) {
6286 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6287 print "$job : finished\n";
6288 delete $jobs->{$job};
6292 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6294 my $busy = $running_mirror_jobs->{$job}->{busy
};
6295 my $ready = $running_mirror_jobs->{$job}->{ready
};
6296 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6297 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6298 my $remaining = $total - $transferred;
6299 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6301 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6304 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6307 last if scalar(keys %$jobs) == 0;
6309 if ($readycounter == scalar(keys %$jobs)) {
6310 print "all mirroring jobs are ready \n";
6311 last if $skipcomplete; #do the complete later
6313 if ($vmiddst && $vmiddst != $vmid) {
6314 my $agent_running = $qga && qga_check_running
($vmid);
6315 if ($agent_running) {
6316 print "freeze filesystem\n";
6317 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6319 print "suspend vm\n";
6320 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6323 # if we clone a disk for a new target vm, we don't switch the disk
6324 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6326 if ($agent_running) {
6327 print "unfreeze filesystem\n";
6328 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6330 print "resume vm\n";
6331 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6337 foreach my $job (keys %$jobs) {
6338 # try to switch the disk if source and destination are on the same guest
6339 print "$job: Completing block job...\n";
6341 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6342 if ($@ =~ m/cannot be completed/) {
6343 print "$job: Block job cannot be completed, try again.\n";
6346 print "$job: Completed successfully.\n";
6347 $jobs->{$job}->{complete
} = 1;
6358 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6359 die "mirroring error: $err";
6364 sub qemu_blockjobs_cancel
{
6365 my ($vmid, $jobs) = @_;
6367 foreach my $job (keys %$jobs) {
6368 print "$job: Cancelling block job\n";
6369 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6370 $jobs->{$job}->{cancel
} = 1;
6374 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6376 my $running_jobs = {};
6377 foreach my $stat (@$stats) {
6378 $running_jobs->{$stat->{device
}} = $stat;
6381 foreach my $job (keys %$jobs) {
6383 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6384 print "$job: Done.\n";
6385 delete $jobs->{$job};
6389 last if scalar(keys %$jobs) == 0;
6396 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6397 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;
6402 print "create linked clone of drive $drivename ($drive->{file})\n";
6403 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6404 push @$newvollist, $newvolid;
6407 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6408 $storeid = $storage if $storage;
6410 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
6411 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6413 print "create full clone of drive $drivename ($drive->{file})\n";
6415 if (drive_is_cloudinit
($drive)) {
6416 $name = "vm-$newvmid-cloudinit";
6417 # cloudinit only supports raw and qcow2 atm:
6418 if ($dst_format eq 'qcow2') {
6420 } elsif ($dst_format ne 'raw') {
6421 die "clone: unhandled format for cloudinit image\n";
6424 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
6425 push @$newvollist, $newvolid;
6427 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6429 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6430 if (!$running || $snapname) {
6431 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6434 my $kvmver = get_running_qemu_version
($vmid);
6435 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
6436 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6437 if $drive->{iothread
};
6440 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga);
6444 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6447 $disk->{format
} = undef;
6448 $disk->{file
} = $newvolid;
6449 $disk->{size
} = $size;
6454 # this only works if VM is running
6455 sub get_current_qemu_machine
{
6458 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
6459 my $res = vm_qmp_command
($vmid, $cmd);
6461 my ($current, $default);
6462 foreach my $e (@$res) {
6463 $default = $e->{name
} if $e->{'is-default'};
6464 $current = $e->{name
} if $e->{'is-current'};
6467 # fallback to the default machine if current is not supported by qemu
6468 return $current || $default || 'pc';
6471 sub get_running_qemu_version
{
6473 my $cmd = { execute
=> 'query-version', arguments
=> {} };
6474 my $res = vm_qmp_command
($vmid, $cmd);
6475 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6478 sub qemu_machine_feature_enabled
{
6479 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6484 if ($machine && $machine =~ m/^(pc(-i440fx|-q35)?-(\d+)\.(\d+))/) {
6486 $current_major = $3;
6487 $current_minor = $4;
6489 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6491 $current_major = $1;
6492 $current_minor = $2;
6495 return 1 if $current_major >= $version_major && $current_minor >= $version_minor;
6500 sub qemu_machine_pxe
{
6501 my ($vmid, $conf, $machine) = @_;
6503 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6505 foreach my $opt (keys %$conf) {
6506 next if $opt !~ m/^net(\d+)$/;
6507 my $net = PVE
::QemuServer
::parse_net
($conf->{$opt});
6509 my $romfile = PVE
::QemuServer
::vm_mon_cmd_nocheck
($vmid, 'qom-get', path
=> $opt, property
=> 'romfile');
6510 return $machine.".pxe" if $romfile =~ m/pxe/;
6517 sub qemu_use_old_bios_files
{
6518 my ($machine_type) = @_;
6520 return if !$machine_type;
6522 my $use_old_bios_files = undef;
6524 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6526 $use_old_bios_files = 1;
6528 my $kvmver = kvm_user_version
();
6529 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6530 # load new efi bios files on migration. So this hack is required to allow
6531 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6532 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6533 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6536 return ($use_old_bios_files, $machine_type);
6539 sub create_efidisk
{
6540 my ($storecfg, $storeid, $vmid, $fmt) = @_;
6542 die "EFI vars default image not found\n" if ! -f
$OVMF_VARS;
6544 my $vars_size = PVE
::Tools
::convert_size
(-s
$OVMF_VARS, 'b' => 'kb');
6545 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6546 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6548 my $path = PVE
::Storage
::path
($storecfg, $volid);
6550 run_command
(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $OVMF_VARS, $path]);
6552 die "Copying EFI vars image failed: $@" if $@;
6554 return ($volid, $vars_size);
6561 dir_glob_foreach
("$pcisysfs/devices", '[a-f0-9]{4}:([a-f0-9]{2}:[a-f0-9]{2})\.([0-9])', sub {
6562 my (undef, $id, $function) = @_;
6563 my $res = { id
=> $id, function
=> $function};
6564 push @{$devices->{$id}}, $res;
6567 # Entries should be sorted by functions.
6568 foreach my $id (keys %$devices) {
6569 my $dev = $devices->{$id};
6570 $devices->{$id} = [ sort { $a->{function
} <=> $b->{function
} } @$dev ];
6576 sub vm_iothreads_list
{
6579 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6582 foreach my $iothread (@$res) {
6583 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6590 my ($conf, $drive) = @_;
6594 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
6596 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6602 my $controller = int($drive->{index} / $maxdev);
6603 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6605 return ($maxdev, $controller, $controller_prefix);
6608 sub add_hyperv_enlightenments
{
6609 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough) = @_;
6611 return if $winversion < 6;
6612 return if $bios && $bios eq 'ovmf' && $winversion < 8;
6614 push @$cpuFlags , 'hv_vendor_id=proxmox' if $gpu_passthrough;
6616 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
6617 push @$cpuFlags , 'hv_spinlocks=0x1fff';
6618 push @$cpuFlags , 'hv_vapic';
6619 push @$cpuFlags , 'hv_time';
6621 push @$cpuFlags , 'hv_spinlocks=0xffff';
6624 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
6625 push @$cpuFlags , 'hv_reset';
6626 push @$cpuFlags , 'hv_vpindex';
6627 push @$cpuFlags , 'hv_runtime';
6630 if ($winversion >= 7) {
6631 push @$cpuFlags , 'hv_relaxed';
6635 sub windows_version
{
6638 return 0 if !$ostype;
6642 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6644 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6646 } elsif ($ostype =~ m/^win(\d+)$/) {
6653 sub resolve_dst_disk_format
{
6654 my ($storecfg, $storeid, $src_volname, $format) = @_;
6655 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6658 # if no target format is specified, use the source disk format as hint
6660 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6661 $format = qemu_img_format
($scfg, $src_volname);
6667 # test if requested format is supported - else use default
6668 my $supported = grep { $_ eq $format } @$validFormats;
6669 $format = $defFormat if !$supported;
6673 sub resolve_first_disk
{
6675 my @disks = PVE
::QemuServer
::valid_drive_names
();
6677 foreach my $ds (reverse @disks) {
6678 next if !$conf->{$ds};
6679 my $disk = PVE
::QemuServer
::parse_drive
($ds, $conf->{$ds});
6680 next if PVE
::QemuServer
::drive_is_cdrom
($disk);
6686 sub generate_smbios1_uuid
{
6687 my ($uuid, $uuid_str);
6688 UUID
::generate
($uuid);
6689 UUID
::unparse
($uuid, $uuid_str);
6690 return "uuid=$uuid_str";
6693 # bash completion helper
6695 sub complete_backup_archives
{
6696 my ($cmdname, $pname, $cvalue) = @_;
6698 my $cfg = PVE
::Storage
::config
();
6702 if ($cvalue =~ m/^([^:]+):/) {
6706 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
6709 foreach my $id (keys %$data) {
6710 foreach my $item (@{$data->{$id}}) {
6711 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
6712 push @$res, $item->{volid
} if defined($item->{volid
});
6719 my $complete_vmid_full = sub {
6722 my $idlist = vmstatus
();
6726 foreach my $id (keys %$idlist) {
6727 my $d = $idlist->{$id};
6728 if (defined($running)) {
6729 next if $d->{template
};
6730 next if $running && $d->{status
} ne 'running';
6731 next if !$running && $d->{status
} eq 'running';
6740 return &$complete_vmid_full();
6743 sub complete_vmid_stopped
{
6744 return &$complete_vmid_full(0);
6747 sub complete_vmid_running
{
6748 return &$complete_vmid_full(1);
6751 sub complete_storage
{
6753 my $cfg = PVE
::Storage
::config
();
6754 my $ids = $cfg->{ids
};
6757 foreach my $sid (keys %$ids) {
6758 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
6759 next if !$ids->{$sid}->{content
}->{images
};