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;
3096 my $vmname = $conf->{name
} || "vm$vmid";
3098 push @$cmd, '-name', $vmname;
3102 my $qmpsocket = qmp_socket
($vmid);
3103 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3104 push @$cmd, '-mon', "chardev=qmp,mode=control";
3107 push @$cmd, '-pidfile' , pidfile_name
($vmid);
3109 push @$cmd, '-daemonize';
3111 if ($conf->{smbios1
}) {
3112 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3115 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3116 die "uefi base image not found\n" if ! -f
$OVMF_CODE;
3120 if (my $efidisk = $conf->{efidisk0
}) {
3121 my $d = PVE
::JSONSchema
::parse_property_string
($efidisk_fmt, $efidisk);
3122 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3123 $format = $d->{format
};
3125 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3126 if (!defined($format)) {
3127 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3128 $format = qemu_img_format
($scfg, $volname);
3132 die "efidisk format must be specified\n"
3133 if !defined($format);
3136 warn "no efidisk configured! Using temporary efivars disk.\n";
3137 $path = "/tmp/$vmid-ovmf.fd";
3138 PVE
::Tools
::file_copy
($OVMF_VARS, $path, -s
$OVMF_VARS);
3142 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$OVMF_CODE";
3143 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
3147 # add usb controllers
3148 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $q35, $usbdesc->{format
}, $MAX_USB_DEVICES);
3149 push @$devices, @usbcontrollers if @usbcontrollers;
3150 my $vga = $conf->{vga
};
3152 my $qxlnum = vga_conf_has_spice
($vga);
3153 $vga = 'qxl' if $qxlnum;
3156 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 9)) {
3157 $vga = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3159 $vga = ($winversion >= 6) ?
'std' : 'cirrus';
3163 # enable absolute mouse coordinates (needed by vnc)
3165 if (defined($conf->{tablet
})) {
3166 $tablet = $conf->{tablet
};
3168 $tablet = $defaults->{tablet
};
3169 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3170 $tablet = 0 if $vga =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3173 push @$devices, '-device', print_tabletdevice_full
($conf) if $tablet;
3176 my $gpu_passthrough;
3179 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3180 my $d = parse_hostpci
($conf->{"hostpci$i"});
3183 my $pcie = $d->{pcie
};
3185 die "q35 machine model is not enabled" if !$q35;
3186 $pciaddr = print_pcie_addr
("hostpci$i");
3188 $pciaddr = print_pci_addr
("hostpci$i", $bridges);
3191 my $rombar = defined($d->{rombar
}) && !$d->{rombar
} ?
',rombar=0' : '';
3192 my $romfile = $d->{romfile
};
3195 if ($d->{'x-vga'}) {
3196 $xvga = ',x-vga=on';
3199 $gpu_passthrough = 1;
3201 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3205 my $pcidevices = $d->{pciid
};
3206 my $multifunction = 1 if @$pcidevices > 1;
3209 foreach my $pcidevice (@$pcidevices) {
3211 my $id = "hostpci$i";
3212 $id .= ".$j" if $multifunction;
3213 my $addr = $pciaddr;
3214 $addr .= ".$j" if $multifunction;
3215 my $devicestr = "vfio-pci,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
3218 $devicestr .= "$rombar$xvga";
3219 $devicestr .= ",multifunction=on" if $multifunction;
3220 $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
3223 push @$devices, '-device', $devicestr;
3229 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES);
3230 push @$devices, @usbdevices if @usbdevices;
3232 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3233 if (my $path = $conf->{"serial$i"}) {
3234 if ($path eq 'socket') {
3235 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3236 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3237 push @$devices, '-device', "isa-serial,chardev=serial$i";
3239 die "no such serial device\n" if ! -c
$path;
3240 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3241 push @$devices, '-device', "isa-serial,chardev=serial$i";
3247 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3248 if (my $path = $conf->{"parallel$i"}) {
3249 die "no such parallel device\n" if ! -c
$path;
3250 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3251 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3252 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3258 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3259 $sockets = $conf->{sockets
} if $conf->{sockets
};
3261 my $cores = $conf->{cores
} || 1;
3263 my $maxcpus = $sockets * $cores;
3265 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3267 my $allowed_vcpus = $cpuinfo->{cpus
};
3269 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3270 if ($allowed_vcpus < $maxcpus);
3272 if($hotplug_features->{cpu
} && qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 7)) {
3274 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3275 for (my $i = 2; $i <= $vcpus; $i++) {
3276 my $cpustr = print_cpu_device
($conf,$i);
3277 push @$cmd, '-device', $cpustr;
3282 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3284 push @$cmd, '-nodefaults';
3286 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3288 my $bootindex_hash = {};
3290 foreach my $o (split(//, $bootorder)) {
3291 $bootindex_hash->{$o} = $i*100;
3295 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3297 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3299 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3301 push @$cmd, '-vga', $vga if $vga && $vga !~ m/^serial\d+$/; # for kvm 77 and later
3303 if ($vga && $vga !~ m/^serial\d+$/ && $vga ne 'none'){
3304 my $socket = vnc_socket
($vmid);
3305 push @$cmd, '-vnc', "unix:$socket,x509,password";
3307 push @$cmd, '-nographic';
3311 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3313 my $useLocaltime = $conf->{localtime};
3315 if ($winversion >= 5) { # windows
3316 $useLocaltime = 1 if !defined($conf->{localtime});
3318 # use time drift fix when acpi is enabled
3319 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3320 $tdf = 1 if !defined($conf->{tdf
});
3324 if ($winversion >= 6) {
3325 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3326 push @$cmd, '-no-hpet';
3329 push @$rtcFlags, 'driftfix=slew' if $tdf;
3332 push @$machineFlags, 'accel=tcg';
3335 if ($machine_type) {
3336 push @$machineFlags, "type=${machine_type}";
3339 if ($conf->{startdate
}) {
3340 push @$rtcFlags, "base=$conf->{startdate}";
3341 } elsif ($useLocaltime) {
3342 push @$rtcFlags, 'base=localtime';
3345 my $cpu = $kvm ?
"kvm64" : "qemu64";
3346 if (my $cputype = $conf->{cpu
}) {
3347 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
3348 or die "Cannot parse cpu description: $cputype\n";
3349 $cpu = $cpuconf->{cputype
};
3350 $kvm_off = 1 if $cpuconf->{hidden
};
3352 if (defined(my $flags = $cpuconf->{flags
})) {
3353 push @$cpuFlags, split(";", $flags);
3357 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64';
3359 push @$cpuFlags , '-x2apic'
3360 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3362 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3364 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3366 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3368 push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
3369 push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
3372 add_hyperv_enlightenments
($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios
}, $gpu_passthrough) if $kvm;
3374 push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm;
3376 push @$cpuFlags, 'kvm=off' if $kvm_off;
3378 my $cpu_vendor = $cpu_vendor_list->{$cpu} ||
3379 die "internal error"; # should not happen
3381 push @$cpuFlags, "vendor=${cpu_vendor}"
3382 if $cpu_vendor ne 'default';
3384 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3386 push @$cmd, '-cpu', $cpu;
3388 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3390 push @$cmd, '-S' if $conf->{freeze
};
3392 # set keyboard layout
3393 my $kb = $conf->{keyboard
} || $defaults->{keyboard
};
3394 push @$cmd, '-k', $kb if $kb;
3397 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3398 #push @$cmd, '-soundhw', 'es1370';
3399 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3401 if($conf->{agent
}) {
3402 my $qgasocket = qmp_socket
($vmid, 1);
3403 my $pciaddr = print_pci_addr
("qga0", $bridges);
3404 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3405 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3406 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3414 for(my $i = 1; $i < $qxlnum; $i++){
3415 my $pciaddr = print_pci_addr
("vga$i", $bridges);
3416 push @$cmd, '-device', "qxl,id=vga$i,ram_size=67108864,vram_size=33554432$pciaddr";
3419 # assume other OS works like Linux
3420 push @$cmd, '-global', 'qxl-vga.ram_size=134217728';
3421 push @$cmd, '-global', 'qxl-vga.vram_size=67108864';
3425 my $pciaddr = print_pci_addr
("spice", $bridges);
3427 my $nodename = PVE
::INotify
::nodename
();
3428 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3429 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3430 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3431 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3432 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3434 push @$devices, '-spice', "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3436 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3437 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3438 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3441 # enable balloon by default, unless explicitly disabled
3442 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3443 $pciaddr = print_pci_addr
("balloon0", $bridges);
3444 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3447 if ($conf->{watchdog
}) {
3448 my $wdopts = parse_watchdog
($conf->{watchdog
});
3449 $pciaddr = print_pci_addr
("watchdog", $bridges);
3450 my $watchdog = $wdopts->{model
} || 'i6300esb';
3451 push @$devices, '-device', "$watchdog$pciaddr";
3452 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3456 my $scsicontroller = {};
3457 my $ahcicontroller = {};
3458 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3460 # Add iscsi initiator name if available
3461 if (my $initiator = get_initiator_name
()) {
3462 push @$devices, '-iscsi', "initiator-name=$initiator";
3465 foreach_drive
($conf, sub {
3466 my ($ds, $drive) = @_;
3468 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3469 push @$vollist, $drive->{file
};
3472 # ignore efidisk here, already added in bios/fw handling code above
3473 return if $drive->{interface
} eq 'efidisk';
3475 $use_virtio = 1 if $ds =~ m/^virtio/;
3477 if (drive_is_cdrom
($drive)) {
3478 if ($bootindex_hash->{d
}) {
3479 $drive->{bootindex
} = $bootindex_hash->{d
};
3480 $bootindex_hash->{d
} += 1;
3483 if ($bootindex_hash->{c
}) {
3484 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3485 $bootindex_hash->{c
} += 1;
3489 if($drive->{interface
} eq 'virtio'){
3490 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3493 if ($drive->{interface
} eq 'scsi') {
3495 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3497 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges);
3498 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3501 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3502 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3503 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3504 } elsif ($drive->{iothread
}) {
3505 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3509 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3510 $queues = ",num_queues=$drive->{queues}";
3513 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3514 $scsicontroller->{$controller}=1;
3517 if ($drive->{interface
} eq 'sata') {
3518 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3519 $pciaddr = print_pci_addr
("ahci$controller", $bridges);
3520 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3521 $ahcicontroller->{$controller}=1;
3524 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3525 push @$devices, '-drive',$drive_cmd;
3526 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges);
3529 for (my $i = 0; $i < $MAX_NETS; $i++) {
3530 next if !$conf->{"net$i"};
3531 my $d = parse_net
($conf->{"net$i"});
3534 $use_virtio = 1 if $d->{model
} eq 'virtio';
3536 if ($bootindex_hash->{n
}) {
3537 $d->{bootindex
} = $bootindex_hash->{n
};
3538 $bootindex_hash->{n
} += 1;
3541 my $netdevfull = print_netdev_full
($vmid,$conf,$d,"net$i");
3542 push @$devices, '-netdev', $netdevfull;
3544 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files);
3545 push @$devices, '-device', $netdevicefull;
3550 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3555 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3557 while (my ($k, $v) = each %$bridges) {
3558 $pciaddr = print_pci_addr
("pci.$k");
3559 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3564 if ($conf->{args
}) {
3565 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3569 push @$cmd, @$devices;
3570 push @$cmd, '-rtc', join(',', @$rtcFlags)
3571 if scalar(@$rtcFlags);
3572 push @$cmd, '-machine', join(',', @$machineFlags)
3573 if scalar(@$machineFlags);
3574 push @$cmd, '-global', join(',', @$globalFlags)
3575 if scalar(@$globalFlags);
3577 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3582 return "${var_run_tmpdir}/$vmid.vnc";
3588 my $res = vm_mon_cmd
($vmid, 'query-spice');
3590 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3594 my ($vmid, $qga) = @_;
3595 my $sockettype = $qga ?
'qga' : 'qmp';
3596 return "${var_run_tmpdir}/$vmid.$sockettype";
3601 return "${var_run_tmpdir}/$vmid.pid";
3604 sub vm_devices_list
{
3607 my $res = vm_mon_cmd
($vmid, 'query-pci');
3609 foreach my $pcibus (@$res) {
3610 foreach my $device (@{$pcibus->{devices
}}) {
3611 next if !$device->{'qdev_id'};
3612 if ($device->{'pci_bridge'}) {
3613 $devices->{$device->{'qdev_id'}} = 1;
3614 foreach my $bridge_device (@{$device->{'pci_bridge'}->{devices
}}) {
3615 next if !$bridge_device->{'qdev_id'};
3616 $devices->{$bridge_device->{'qdev_id'}} = 1;
3617 $devices->{$device->{'qdev_id'}}++;
3620 $devices->{$device->{'qdev_id'}} = 1;
3625 my $resblock = vm_mon_cmd
($vmid, 'query-block');
3626 foreach my $block (@$resblock) {
3627 if($block->{device
} =~ m/^drive-(\S+)/){
3632 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
3633 foreach my $mice (@$resmice) {
3634 if ($mice->{name
} eq 'QEMU HID Tablet') {
3635 $devices->{tablet
} = 1;
3640 # for usb devices there is no query-usb
3641 # but we can iterate over the entries in
3642 # qom-list path=/machine/peripheral
3643 my $resperipheral = vm_mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3644 foreach my $per (@$resperipheral) {
3645 if ($per->{name
} =~ m/^usb\d+$/) {
3646 $devices->{$per->{name
}} = 1;
3654 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
3656 my $q35 = machine_type_is_q35
($conf);
3658 my $devices_list = vm_devices_list
($vmid);
3659 return 1 if defined($devices_list->{$deviceid});
3661 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid); # add PCI bridge if we need it for the device
3663 if ($deviceid eq 'tablet') {
3665 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf));
3667 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3669 die "usb hotplug currently not reliable\n";
3670 # since we can't reliably hot unplug all added usb devices
3671 # and usb passthrough disables live migration
3672 # we disable usb hotplugging for now
3673 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
3675 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3677 qemu_iothread_add
($vmid, $deviceid, $device);
3679 qemu_driveadd
($storecfg, $vmid, $device);
3680 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3682 qemu_deviceadd
($vmid, $devicefull);
3683 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3685 eval { qemu_drivedel
($vmid, $deviceid); };
3690 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3693 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
3694 my $pciaddr = print_pci_addr
($deviceid);
3695 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
3697 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
3699 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
3700 qemu_iothread_add
($vmid, $deviceid, $device);
3701 $devicefull .= ",iothread=iothread-$deviceid";
3704 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
3705 $devicefull .= ",num_queues=$device->{queues}";
3708 qemu_deviceadd
($vmid, $devicefull);
3709 qemu_deviceaddverify
($vmid, $deviceid);
3711 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3713 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device);
3714 qemu_driveadd
($storecfg, $vmid, $device);
3716 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3717 eval { qemu_deviceadd
($vmid, $devicefull); };
3719 eval { qemu_drivedel
($vmid, $deviceid); };
3724 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3726 return undef if !qemu_netdevadd
($vmid, $conf, $device, $deviceid);
3728 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
3729 my $use_old_bios_files = undef;
3730 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3732 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files);
3733 qemu_deviceadd
($vmid, $netdevicefull);
3734 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3736 eval { qemu_netdevdel
($vmid, $deviceid); };
3741 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
3744 my $pciaddr = print_pci_addr
($deviceid);
3745 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
3747 qemu_deviceadd
($vmid, $devicefull);
3748 qemu_deviceaddverify
($vmid, $deviceid);
3751 die "can't hotplug device '$deviceid'\n";
3757 # fixme: this should raise exceptions on error!
3758 sub vm_deviceunplug
{
3759 my ($vmid, $conf, $deviceid) = @_;
3761 my $devices_list = vm_devices_list
($vmid);
3762 return 1 if !defined($devices_list->{$deviceid});
3764 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
3766 if ($deviceid eq 'tablet') {
3768 qemu_devicedel
($vmid, $deviceid);
3770 } elsif ($deviceid =~ m/^usb\d+$/) {
3772 die "usb hotplug currently not reliable\n";
3773 # when unplugging usb devices this way,
3774 # there may be remaining usb controllers/hubs
3775 # so we disable it for now
3776 qemu_devicedel
($vmid, $deviceid);
3777 qemu_devicedelverify
($vmid, $deviceid);
3779 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3781 qemu_devicedel
($vmid, $deviceid);
3782 qemu_devicedelverify
($vmid, $deviceid);
3783 qemu_drivedel
($vmid, $deviceid);
3784 qemu_iothread_del
($conf, $vmid, $deviceid);
3786 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3788 qemu_devicedel
($vmid, $deviceid);
3789 qemu_devicedelverify
($vmid, $deviceid);
3790 qemu_iothread_del
($conf, $vmid, $deviceid);
3792 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3794 qemu_devicedel
($vmid, $deviceid);
3795 qemu_drivedel
($vmid, $deviceid);
3796 qemu_deletescsihw
($conf, $vmid, $deviceid);
3798 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3800 qemu_devicedel
($vmid, $deviceid);
3801 qemu_devicedelverify
($vmid, $deviceid);
3802 qemu_netdevdel
($vmid, $deviceid);
3805 die "can't unplug device '$deviceid'\n";
3811 sub qemu_deviceadd
{
3812 my ($vmid, $devicefull) = @_;
3814 $devicefull = "driver=".$devicefull;
3815 my %options = split(/[=,]/, $devicefull);
3817 vm_mon_cmd
($vmid, "device_add" , %options);
3820 sub qemu_devicedel
{
3821 my ($vmid, $deviceid) = @_;
3823 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
3826 sub qemu_iothread_add
{
3827 my($vmid, $deviceid, $device) = @_;
3829 if ($device->{iothread
}) {
3830 my $iothreads = vm_iothreads_list
($vmid);
3831 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
3835 sub qemu_iothread_del
{
3836 my($conf, $vmid, $deviceid) = @_;
3838 my $device = parse_drive
($deviceid, $conf->{$deviceid});
3839 if ($device->{iothread
}) {
3840 my $iothreads = vm_iothreads_list
($vmid);
3841 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
3845 sub qemu_objectadd
{
3846 my($vmid, $objectid, $qomtype) = @_;
3848 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
3853 sub qemu_objectdel
{
3854 my($vmid, $objectid) = @_;
3856 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
3862 my ($storecfg, $vmid, $device) = @_;
3864 my $drive = print_drive_full
($storecfg, $vmid, $device);
3865 $drive =~ s/\\/\\\\/g;
3866 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
3868 # If the command succeeds qemu prints: "OK
"
3869 return 1 if $ret =~ m/OK/s;
3871 die "adding drive failed
: $ret\n";
3875 my($vmid, $deviceid) = @_;
3877 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
3880 return 1 if $ret eq "";
3882 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
3883 return 1 if $ret =~ m/Device \'.*?\' not found/s;
3885 die "deleting drive
$deviceid failed
: $ret\n";
3888 sub qemu_deviceaddverify {
3889 my ($vmid, $deviceid) = @_;
3891 for (my $i = 0; $i <= 5; $i++) {
3892 my $devices_list = vm_devices_list($vmid);
3893 return 1 if defined($devices_list->{$deviceid});
3897 die "error on hotplug device
'$deviceid'\n";
3901 sub qemu_devicedelverify {
3902 my ($vmid, $deviceid) = @_;
3904 # need to verify that the device is correctly removed as device_del
3905 # is async and empty return is not reliable
3907 for (my $i = 0; $i <= 5; $i++) {
3908 my $devices_list = vm_devices_list($vmid);
3909 return 1 if !defined($devices_list->{$deviceid});
3913 die "error on hot-unplugging device
'$deviceid'\n";
3916 sub qemu_findorcreatescsihw {
3917 my ($storecfg, $conf, $vmid, $device) = @_;
3919 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3921 my $scsihwid="$controller_prefix$controller";
3922 my $devices_list = vm_devices_list($vmid);
3924 if(!defined($devices_list->{$scsihwid})) {
3925 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device);
3931 sub qemu_deletescsihw {
3932 my ($conf, $vmid, $opt) = @_;
3934 my $device = parse_drive($opt, $conf->{$opt});
3936 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
3937 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
3941 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3943 my $devices_list = vm_devices_list($vmid);
3944 foreach my $opt (keys %{$devices_list}) {
3945 if (PVE::QemuServer::is_valid_drivename($opt)) {
3946 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
3947 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
3953 my $scsihwid="scsihw
$controller";
3955 vm_deviceunplug($vmid, $conf, $scsihwid);
3960 sub qemu_add_pci_bridge {
3961 my ($storecfg, $conf, $vmid, $device) = @_;
3967 print_pci_addr($device, $bridges);
3969 while (my ($k, $v) = each %$bridges) {
3972 return 1 if !defined($bridgeid) || $bridgeid < 1;
3974 my $bridge = "pci
.$bridgeid";
3975 my $devices_list = vm_devices_list($vmid);
3977 if (!defined($devices_list->{$bridge})) {
3978 vm_deviceplug($storecfg, $conf, $vmid, $bridge);
3984 sub qemu_set_link_status {
3985 my ($vmid, $device, $up) = @_;
3987 vm_mon_cmd($vmid, "set_link
", name => $device,
3988 up => $up ? JSON::true : JSON::false);
3991 sub qemu_netdevadd {
3992 my ($vmid, $conf, $device, $deviceid) = @_;
3994 my $netdev = print_netdev_full($vmid, $conf, $device, $deviceid, 1);
3995 my %options = split(/[=,]/, $netdev);
3997 vm_mon_cmd($vmid, "netdev_add
", %options);
4001 sub qemu_netdevdel {
4002 my ($vmid, $deviceid) = @_;
4004 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
4007 sub qemu_usb_hotplug {
4008 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
4012 # remove the old one first
4013 vm_deviceunplug($vmid, $conf, $deviceid);
4015 # check if xhci controller is necessary and available
4016 if ($device->{usb3}) {
4018 my $devicelist = vm_devices_list($vmid);
4020 if (!$devicelist->{xhci}) {
4021 my $pciaddr = print_pci_addr("xhci
");
4022 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4025 my $d = parse_usb_device($device->{host});
4026 $d->{usb3} = $device->{usb3};
4029 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d);
4032 sub qemu_cpu_hotplug {
4033 my ($vmid, $conf, $vcpus) = @_;
4035 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4038 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4039 $sockets = $conf->{sockets} if $conf->{sockets};
4040 my $cores = $conf->{cores} || 1;
4041 my $maxcpus = $sockets * $cores;
4043 $vcpus = $maxcpus if !$vcpus;
4045 die "you can
't add more vcpus than maxcpus\n"
4046 if $vcpus > $maxcpus;
4048 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4050 if ($vcpus < $currentvcpus) {
4052 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4054 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4055 qemu_devicedel($vmid, "cpu$i");
4057 my $currentrunningvcpus = undef;
4059 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4060 last if scalar(@{$currentrunningvcpus}) == $i-1;
4061 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4065 #update conf after each succesfull cpu unplug
4066 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4067 PVE::QemuConfig->write_config($vmid, $conf);
4070 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4076 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4077 die "vcpus in running vm does not match its configuration\n"
4078 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4080 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4082 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4083 my $cpustr = print_cpu_device($conf, $i);
4084 qemu_deviceadd($vmid, $cpustr);
4087 my $currentrunningvcpus = undef;
4089 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4090 last if scalar(@{$currentrunningvcpus}) == $i;
4091 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4095 #update conf after each succesfull cpu hotplug
4096 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4097 PVE::QemuConfig->write_config($vmid, $conf);
4101 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4102 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4107 sub qemu_block_set_io_throttle {
4108 my ($vmid, $deviceid,
4109 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4110 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4111 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4112 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4114 return if !check_running($vmid) ;
4116 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4118 bps_rd => int($bps_rd),
4119 bps_wr => int($bps_wr),
4121 iops_rd => int($iops_rd),
4122 iops_wr => int($iops_wr),
4123 bps_max => int($bps_max),
4124 bps_rd_max => int($bps_rd_max),
4125 bps_wr_max => int($bps_wr_max),
4126 iops_max => int($iops_max),
4127 iops_rd_max => int($iops_rd_max),
4128 iops_wr_max => int($iops_wr_max),
4129 bps_max_length => int($bps_max_length),
4130 bps_rd_max_length => int($bps_rd_max_length),
4131 bps_wr_max_length => int($bps_wr_max_length),
4132 iops_max_length => int($iops_max_length),
4133 iops_rd_max_length => int($iops_rd_max_length),
4134 iops_wr_max_length => int($iops_wr_max_length),
4139 # old code, only used to shutdown old VM after update
4141 my ($fh, $timeout) = @_;
4143 my $sel = new IO::Select;
4150 while (scalar (@ready = $sel->can_read($timeout))) {
4152 if ($count = $fh->sysread($buf, 8192)) {
4153 if ($buf =~ /^(.*)\(qemu\) $/s) {
4160 if (!defined($count)) {
4167 die "monitor read timeout\n" if !scalar(@ready);
4172 # old code, only used to shutdown old VM after update
4173 sub vm_monitor_command {
4174 my ($vmid, $cmdstr, $nocheck) = @_;
4179 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
4181 my $sname = "${var_run_tmpdir}/$vmid.mon";
4183 my $sock = IO::Socket::UNIX->new( Peer => $sname ) ||
4184 die "unable to connect to VM $vmid socket - $!\n";
4188 # hack: migrate sometime blocks the monitor (when migrate_downtime
4190 if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
4191 $timeout = 60*60; # 1 hour
4195 my $data = __read_avail($sock, $timeout);
4197 if ($data !~ m/^QEMU\s+(\S+)\s+monitor\s/) {
4198 die "got unexpected qemu monitor banner\n";
4201 my $sel = new IO::Select;
4204 if (!scalar(my @ready = $sel->can_write($timeout))) {
4205 die "monitor write error - timeout";
4208 my $fullcmd = "$cmdstr\r";
4210 # syslog('info
', "VM $vmid monitor command: $cmdstr");
4213 if (!($b = $sock->syswrite($fullcmd)) || ($b != length($fullcmd))) {
4214 die "monitor write error - $!";
4217 return if ($cmdstr eq 'q
') || ($cmdstr eq 'quit
');
4221 if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
4222 $timeout = 60*60; # 1 hour
4223 } elsif ($cmdstr =~ m/^(eject|change)/) {
4224 $timeout = 60; # note: cdrom mount command is slow
4226 if ($res = __read_avail($sock, $timeout)) {
4228 my @lines = split("\r?\n", $res);
4230 shift @lines if $lines[0] !~ m/^unknown command/; # skip echo
4232 $res = join("\n", @lines);
4240 syslog("err", "VM $vmid monitor command failed - $err");
4247 sub qemu_block_resize {
4248 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4250 my $running = check_running($vmid);
4252 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4254 return if !$running;
4256 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4260 sub qemu_volume_snapshot {
4261 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4263 my $running = check_running($vmid);
4265 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4266 vm_mon_cmd($vmid, "snapshot-drive", device => $deviceid, name => $snap);
4268 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4272 sub qemu_volume_snapshot_delete {
4273 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4275 my $running = check_running($vmid);
4277 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4278 vm_mon_cmd($vmid, "delete-drive-snapshot", device => $deviceid, name => $snap);
4280 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4284 sub set_migration_caps {
4290 "auto-converge" => 1,
4292 "x-rdma-pin-all" => 0,
4297 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4299 for my $supported_capability (@$supported_capabilities) {
4301 capability => $supported_capability->{capability},
4302 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4306 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4309 my $fast_plug_option = {
4317 'vmstatestorage
' => 1,
4320 # hotplug changes in [PENDING]
4321 # $selection hash can be used to only apply specified options, for
4322 # example: { cores => 1 } (only apply changed 'cores
')
4323 # $errors ref is used to return error messages
4324 sub vmconfig_hotplug_pending {
4325 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4327 my $defaults = load_defaults();
4329 # commit values which do not have any impact on running VM first
4330 # Note: those option cannot raise errors, we we do not care about
4331 # $selection and always apply them.
4333 my $add_error = sub {
4334 my ($opt, $msg) = @_;
4335 $errors->{$opt} = "hotplug problem - $msg";
4339 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4340 if ($fast_plug_option->{$opt}) {
4341 $conf->{$opt} = $conf->{pending}->{$opt};
4342 delete $conf->{pending}->{$opt};
4348 PVE::QemuConfig->write_config($vmid, $conf);
4349 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4352 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4354 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4355 while (my ($opt, $force) = each %$pending_delete_hash) {
4356 next if $selection && !$selection->{$opt};
4358 if ($opt eq 'hotplug
') {
4359 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4360 } elsif ($opt eq 'tablet
') {
4361 die "skip\n" if !$hotplug_features->{usb};
4362 if ($defaults->{tablet}) {
4363 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4365 vm_deviceunplug($vmid, $conf, $opt);
4367 } elsif ($opt =~ m/^usb\d+/) {
4369 # since we cannot reliably hot unplug usb devices
4370 # we are disabling it
4371 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4372 vm_deviceunplug($vmid, $conf, $opt);
4373 } elsif ($opt eq 'vcpus
') {
4374 die "skip\n" if !$hotplug_features->{cpu};
4375 qemu_cpu_hotplug($vmid, $conf, undef);
4376 } elsif ($opt eq 'balloon
') {
4377 # enable balloon device is not hotpluggable
4378 die "skip\n" if !defined($conf->{balloon}) || $conf->{balloon};
4379 } elsif ($fast_plug_option->{$opt}) {
4381 } elsif ($opt =~ m/^net(\d+)$/) {
4382 die "skip\n" if !$hotplug_features->{network};
4383 vm_deviceunplug($vmid, $conf, $opt);
4384 } elsif (is_valid_drivename($opt)) {
4385 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4386 vm_deviceunplug($vmid, $conf, $opt);
4387 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4388 } elsif ($opt =~ m/^memory$/) {
4389 die "skip\n" if !$hotplug_features->{memory};
4390 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4391 } elsif ($opt eq 'cpuunits
') {
4392 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4393 } elsif ($opt eq 'cpulimit
') {
4394 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4400 &$add_error($opt, $err) if $err ne "skip\n";
4402 # save new config if hotplug was successful
4403 delete $conf->{$opt};
4404 vmconfig_undelete_pending_option($conf, $opt);
4405 PVE::QemuConfig->write_config($vmid, $conf);
4406 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4410 my $apply_pending_cloudinit;
4411 $apply_pending_cloudinit = sub {
4412 my ($key, $value) = @_;
4413 $apply_pending_cloudinit = sub {}; # once is enough
4415 my @cloudinit_opts = keys %$confdesc_cloudinit;
4416 foreach my $opt (keys %{$conf->{pending}}) {
4417 next if !grep { $_ eq $opt } @cloudinit_opts;
4418 $conf->{$opt} = delete $conf->{pending}->{$opt};
4421 my $new_conf = { %$conf };
4422 $new_conf->{$key} = $value;
4423 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4426 foreach my $opt (keys %{$conf->{pending}}) {
4427 next if $selection && !$selection->{$opt};
4428 my $value = $conf->{pending}->{$opt};
4430 if ($opt eq 'hotplug
') {
4431 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4432 } elsif ($opt eq 'tablet
') {
4433 die "skip\n" if !$hotplug_features->{usb};
4435 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4436 } elsif ($value == 0) {
4437 vm_deviceunplug($vmid, $conf, $opt);
4439 } elsif ($opt =~ m/^usb\d+$/) {
4441 # since we cannot reliably hot unplug usb devices
4442 # we are disabling it
4443 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4444 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4445 die "skip\n" if !$d;
4446 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d);
4447 } elsif ($opt eq 'vcpus
') {
4448 die "skip\n" if !$hotplug_features->{cpu};
4449 qemu_cpu_hotplug($vmid, $conf, $value);
4450 } elsif ($opt eq 'balloon
') {
4451 # enable/disable balloning device is not hotpluggable
4452 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4453 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4454 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4456 # allow manual ballooning if shares is set to zero
4457 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4458 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4459 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4461 } elsif ($opt =~ m/^net(\d+)$/) {
4462 # some changes can be done without hotplug
4463 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4464 $vmid, $opt, $value);
4465 } elsif (is_valid_drivename($opt)) {
4466 # some changes can be done without hotplug
4467 my $drive = parse_drive($opt, $value);
4468 if (drive_is_cloudinit($drive)) {
4469 &$apply_pending_cloudinit($opt, $value);
4471 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4472 $vmid, $opt, $value, 1);
4473 } elsif ($opt =~ m/^memory$/) { #dimms
4474 die "skip\n" if !$hotplug_features->{memory};
4475 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4476 } elsif ($opt eq 'cpuunits
') {
4477 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4478 } elsif ($opt eq 'cpulimit
') {
4479 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4480 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4482 die "skip\n"; # skip non-hot-pluggable options
4486 &$add_error($opt, $err) if $err ne "skip\n";
4488 # save new config if hotplug was successful
4489 $conf->{$opt} = $value;
4490 delete $conf->{pending}->{$opt};
4491 PVE::QemuConfig->write_config($vmid, $conf);
4492 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4497 sub try_deallocate_drive {
4498 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4500 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4501 my $volid = $drive->{file};
4502 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4503 my $sid = PVE::Storage::parse_volume_id($volid);
4504 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4506 # check if the disk is really unused
4507 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4508 if is_volume_in_use($storecfg, $conf, $key, $volid);
4509 PVE::Storage::vdisk_free($storecfg, $volid);
4512 # If vm is not owner of this disk remove from config
4520 sub vmconfig_delete_or_detach_drive {
4521 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4523 my $drive = parse_drive($opt, $conf->{$opt});
4525 my $rpcenv = PVE::RPCEnvironment::get();
4526 my $authuser = $rpcenv->get_user();
4529 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4530 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4532 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4536 sub vmconfig_apply_pending {
4537 my ($vmid, $conf, $storecfg) = @_;
4541 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4542 while (my ($opt, $force) = each %$pending_delete_hash) {
4543 die "internal error" if $opt =~ m/^unused/;
4544 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4545 if (!defined($conf->{$opt})) {
4546 vmconfig_undelete_pending_option($conf, $opt);
4547 PVE::QemuConfig->write_config($vmid, $conf);
4548 } elsif (is_valid_drivename($opt)) {
4549 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4550 vmconfig_undelete_pending_option($conf, $opt);
4551 delete $conf->{$opt};
4552 PVE::QemuConfig->write_config($vmid, $conf);
4554 vmconfig_undelete_pending_option($conf, $opt);
4555 delete $conf->{$opt};
4556 PVE::QemuConfig->write_config($vmid, $conf);
4560 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4562 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4563 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4565 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4566 # skip if nothing changed
4567 } elsif (is_valid_drivename($opt)) {
4568 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4569 if defined($conf->{$opt});
4570 $conf->{$opt} = $conf->{pending}->{$opt};
4572 $conf->{$opt} = $conf->{pending}->{$opt};
4575 delete $conf->{pending}->{$opt};
4576 PVE::QemuConfig->write_config($vmid, $conf);
4580 my $safe_num_ne = sub {
4583 return 0 if !defined($a) && !defined($b);
4584 return 1 if !defined($a);
4585 return 1 if !defined($b);
4590 my $safe_string_ne = sub {
4593 return 0 if !defined($a) && !defined($b);
4594 return 1 if !defined($a);
4595 return 1 if !defined($b);
4600 sub vmconfig_update_net {
4601 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value) = @_;
4603 my $newnet = parse_net($value);
4605 if ($conf->{$opt}) {
4606 my $oldnet = parse_net($conf->{$opt});
4608 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4609 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4610 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4611 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4613 # for non online change, we try to hot-unplug
4614 die "skip\n" if !$hotplug;
4615 vm_deviceunplug($vmid, $conf, $opt);
4618 die "internal error" if $opt !~ m/net(\d+)/;
4619 my $iface = "tap${vmid}i$1";
4621 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4622 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4623 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4624 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4625 PVE::Network::tap_unplug($iface);
4626 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4627 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4628 # Rate can be applied on its own but any change above needs to
4629 # include the rate in tap_plug since OVS resets everything.
4630 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4633 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4634 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4642 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet);
4648 sub vmconfig_update_disk {
4649 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force) = @_;
4651 # fixme: do we need force?
4653 my $drive = parse_drive($opt, $value);
4655 if ($conf->{$opt}) {
4657 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4659 my $media = $drive->{media} || 'disk
';
4660 my $oldmedia = $old_drive->{media} || 'disk
';
4661 die "unable to change media type\n" if $media ne $oldmedia;
4663 if (!drive_is_cdrom($old_drive)) {
4665 if ($drive->{file} ne $old_drive->{file}) {
4667 die "skip\n" if !$hotplug;
4669 # unplug and register as unused
4670 vm_deviceunplug($vmid, $conf, $opt);
4671 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4674 # update existing disk
4676 # skip non hotpluggable value
4677 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4678 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4679 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4680 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
4685 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4686 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4687 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4688 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4689 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4690 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4691 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4692 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4693 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4694 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4695 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4696 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4697 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4698 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4699 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4700 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4701 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4702 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4704 qemu_block_set_io_throttle($vmid,"drive-$opt",
4705 ($drive->{mbps} || 0)*1024*1024,
4706 ($drive->{mbps_rd} || 0)*1024*1024,
4707 ($drive->{mbps_wr} || 0)*1024*1024,
4708 $drive->{iops} || 0,
4709 $drive->{iops_rd} || 0,
4710 $drive->{iops_wr} || 0,
4711 ($drive->{mbps_max} || 0)*1024*1024,
4712 ($drive->{mbps_rd_max} || 0)*1024*1024,
4713 ($drive->{mbps_wr_max} || 0)*1024*1024,
4714 $drive->{iops_max} || 0,
4715 $drive->{iops_rd_max} || 0,
4716 $drive->{iops_wr_max} || 0,
4717 $drive->{bps_max_length} || 1,
4718 $drive->{bps_rd_max_length} || 1,
4719 $drive->{bps_wr_max_length} || 1,
4720 $drive->{iops_max_length} || 1,
4721 $drive->{iops_rd_max_length} || 1,
4722 $drive->{iops_wr_max_length} || 1);
4731 if ($drive->{file} eq 'none
') {
4732 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
4733 if (drive_is_cloudinit($old_drive)) {
4734 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
4737 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4738 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
4739 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
4747 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4749 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
4750 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive);
4754 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
4755 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
4757 PVE::QemuConfig->lock_config($vmid, sub {
4758 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
4760 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
4762 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4764 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
4766 if (!$statefile && scalar(keys %{$conf->{pending}})) {
4767 vmconfig_apply_pending($vmid, $conf, $storecfg);
4768 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4771 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
4773 my $defaults = load_defaults();
4775 # set environment variable useful inside network script
4776 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
4778 my $local_volumes = {};
4780 if ($targetstorage) {
4781 foreach_drive($conf, sub {
4782 my ($ds, $drive) = @_;
4784 return if drive_is_cdrom($drive);
4786 my $volid = $drive->{file};
4790 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
4792 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4793 return if $scfg->{shared};
4794 $local_volumes->{$ds} = [$volid, $storeid, $volname];
4799 foreach my $opt (sort keys %$local_volumes) {
4801 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
4802 my $drive = parse_drive($opt, $conf->{$opt});
4804 #if remote storage is specified, use default format
4805 if ($targetstorage && $targetstorage ne "1") {
4806 $storeid = $targetstorage;
4807 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
4808 $format = $defFormat;
4810 #else we use same format than original
4811 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4812 $format = qemu_img_format($scfg, $volid);
4815 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
4816 my $newdrive = $drive;
4817 $newdrive->{format} = $format;
4818 $newdrive->{file} = $newvolid;
4819 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
4820 $local_volumes->{$opt} = $drivestr;
4821 #pass drive to conf for command line
4822 $conf->{$opt} = $drivestr;
4826 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
4828 my $migrate_port = 0;
4831 if ($statefile eq 'tcp
') {
4832 my $localip = "localhost";
4833 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
4834 my $nodename = PVE::INotify::nodename();
4836 if (!defined($migration_type)) {
4837 if (defined($datacenterconf->{migration}->{type})) {
4838 $migration_type = $datacenterconf->{migration}->{type};
4840 $migration_type = 'secure
';
4844 if ($migration_type eq 'insecure
') {
4845 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
4846 if ($migrate_network_addr) {
4847 $localip = $migrate_network_addr;
4849 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
4852 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4855 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4856 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4857 $migrate_uri = "tcp:${localip}:${migrate_port}";
4858 push @$cmd, '-incoming
', $migrate_uri;
4861 } elsif ($statefile eq 'unix
') {
4862 # should be default for secure migrations as a ssh TCP forward
4863 # tunnel is not deterministic reliable ready and fails regurarly
4864 # to set up in time, so use UNIX socket forwards
4865 my $socket_addr = "/run/qemu-server/$vmid.migrate";
4866 unlink $socket_addr;
4868 $migrate_uri = "unix:$socket_addr";
4870 push @$cmd, '-incoming
', $migrate_uri;
4874 push @$cmd, '-loadstate
', $statefile;
4881 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
4882 my $d = parse_hostpci($conf->{"hostpci$i"});
4884 my $pcidevices = $d->{pciid};
4885 foreach my $pcidevice (@$pcidevices) {
4886 my $pciid = $pcidevice->{id}.".".$pcidevice->{function};
4888 my $info = pci_device_info("0000:$pciid");
4889 die "IOMMU not present\n" if !check_iommu_support();
4890 die "no pci device info for device '$pciid'\n" if !$info;
4891 die "can't unbind
/bind pci group to vfio
'$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
4892 die "can
't reset pci device '$pciid'\n" if $info->{has_fl_reset} and !pci_dev_reset($info);
4896 PVE::Storage::activate_volumes($storecfg, $vollist);
4898 if (!check_running($vmid, 1)) {
4900 run_command(['/bin/systemctl
', 'stop
', "$vmid.scope"],
4901 outfunc => sub {}, errfunc => sub {});
4905 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
4906 : $defaults->{cpuunits};
4908 my $start_timeout = $conf->{hugepages} ? 300 : 30;
4909 my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
4912 Slice => 'qemu
.slice
',
4914 CPUShares => $cpuunits
4917 if (my $cpulimit = $conf->{cpulimit}) {
4918 $properties{CPUQuota} = int($cpulimit * 100);
4920 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
4922 if ($conf->{hugepages}) {
4925 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
4926 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
4928 PVE::QemuServer::Memory::hugepages_mount();
4929 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
4932 PVE::Tools::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4933 run_command($cmd, %run_params);
4937 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
4941 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
4943 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
4947 PVE::Tools::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4948 run_command($cmd, %run_params);
4953 # deactivate volumes if start fails
4954 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
4955 die "start failed: $err";
4958 print "migration listens on $migrate_uri\n" if $migrate_uri;
4960 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
4961 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
4965 #start nbd server for storage migration
4966 if ($targetstorage) {
4967 my $nodename = PVE::INotify::nodename();
4968 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
4969 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
4970 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4971 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4973 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${migrate_port}" } } );
4975 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4977 foreach my $opt (sort keys %$local_volumes) {
4978 my $volid = $local_volumes->{$opt};
4979 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
4980 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
4981 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
4985 if ($migratedfrom) {
4987 set_migration_caps($vmid);
4992 print "spice listens on port $spice_port\n";
4993 if ($spice_ticket) {
4994 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
4995 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
5000 if (!$statefile && (!defined($conf->{balloon}) || $conf->{balloon})) {
5001 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5002 if $conf->{balloon};
5005 foreach my $opt (keys %$conf) {
5006 next if $opt !~ m/^net\d+$/;
5007 my $nicconf = parse_net($conf->{$opt});
5008 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
5012 vm_mon_cmd_nocheck($vmid, 'qom-set
',
5013 path => "machine/peripheral/balloon0",
5014 property => "guest-stats-polling-interval",
5015 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
5021 my ($vmid, $execute, %params) = @_;
5023 my $cmd = { execute => $execute, arguments => \%params };
5024 vm_qmp_command($vmid, $cmd);
5027 sub vm_mon_cmd_nocheck {
5028 my ($vmid, $execute, %params) = @_;
5030 my $cmd = { execute => $execute, arguments => \%params };
5031 vm_qmp_command($vmid, $cmd, 1);
5034 sub vm_qmp_command {
5035 my ($vmid, $cmd, $nocheck) = @_;
5040 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
5041 $timeout = $cmd->{arguments}->{timeout};
5042 delete $cmd->{arguments}->{timeout};
5046 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
5047 my $sname = qmp_socket($vmid);
5048 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
5049 my $qmpclient = PVE::QMPClient->new();
5051 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
5052 } elsif (-e "${var_run_tmpdir}/$vmid.mon") {
5053 die "can't execute complex command on old monitor
- stop
/start your vm to fix the problem
\n"
5054 if scalar(%{$cmd->{arguments}});
5055 vm_monitor_command($vmid, $cmd->{execute}, $nocheck);
5057 die "unable to
open monitor
socket\n";
5061 syslog("err
", "VM
$vmid qmp command failed
- $err");
5068 sub vm_human_monitor_command {
5069 my ($vmid, $cmdline) = @_;
5074 execute => 'human-monitor-command',
5075 arguments => { 'command-line' => $cmdline},
5078 return vm_qmp_command($vmid, $cmd);
5081 sub vm_commandline {
5082 my ($storecfg, $vmid) = @_;
5084 my $conf = PVE::QemuConfig->load_config($vmid);
5086 my $defaults = load_defaults();
5088 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
5090 return PVE::Tools::cmd2string($cmd);
5094 my ($vmid, $skiplock) = @_;
5096 PVE::QemuConfig->lock_config($vmid, sub {
5098 my $conf = PVE::QemuConfig->load_config($vmid);
5100 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5102 vm_mon_cmd($vmid, "system_reset
");
5106 sub get_vm_volumes {
5110 foreach_volid($conf, sub {
5111 my ($volid, $attr) = @_;
5113 return if $volid =~ m|^/|;
5115 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5118 push @$vollist, $volid;
5124 sub vm_stop_cleanup {
5125 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5130 my $vollist = get_vm_volumes($conf);
5131 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5134 foreach my $ext (qw(mon qmp pid vnc qga)) {
5135 unlink "/var/run/qemu-server/${vmid}.$ext";
5138 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5140 warn $@ if $@; # avoid errors - just warn
5143 # Note: use $nockeck to skip tests if VM configuration file exists.
5144 # We need that when migration VMs to other nodes (files already moved)
5145 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5147 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5149 $force = 1 if !defined($force) && !$shutdown;
5152 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5153 kill 15, $pid if $pid;
5154 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5155 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5159 PVE
::QemuConfig-
>lock_config($vmid, sub {
5161 my $pid = check_running
($vmid, $nocheck);
5166 $conf = PVE
::QemuConfig-
>load_config($vmid);
5167 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5168 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5169 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5170 $timeout = $opts->{down
} if $opts->{down
};
5174 $timeout = 60 if !defined($timeout);
5178 if (defined($conf) && $conf->{agent
}) {
5179 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
5181 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
5184 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
5191 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5196 if ($count >= $timeout) {
5198 warn "VM still running - terminating now with SIGTERM\n";
5201 die "VM quit/powerdown failed - got timeout\n";
5204 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5209 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5212 die "VM quit/powerdown failed\n";
5220 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5225 if ($count >= $timeout) {
5226 warn "VM still running - terminating now with SIGKILL\n";
5231 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5236 my ($vmid, $skiplock) = @_;
5238 PVE
::QemuConfig-
>lock_config($vmid, sub {
5240 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5242 PVE
::QemuConfig-
>check_lock($conf)
5243 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5245 vm_mon_cmd
($vmid, "stop");
5250 my ($vmid, $skiplock, $nocheck) = @_;
5252 PVE
::QemuConfig-
>lock_config($vmid, sub {
5256 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5258 PVE
::QemuConfig-
>check_lock($conf)
5259 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5261 vm_mon_cmd
($vmid, "cont");
5264 vm_mon_cmd_nocheck
($vmid, "cont");
5270 my ($vmid, $skiplock, $key) = @_;
5272 PVE
::QemuConfig-
>lock_config($vmid, sub {
5274 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5276 # there is no qmp command, so we use the human monitor command
5277 vm_human_monitor_command
($vmid, "sendkey $key");
5282 my ($storecfg, $vmid, $skiplock) = @_;
5284 PVE
::QemuConfig-
>lock_config($vmid, sub {
5286 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5288 if (!check_running
($vmid)) {
5289 destroy_vm
($storecfg, $vmid, undef, $skiplock);
5291 die "VM $vmid is running - destroy failed\n";
5299 my ($filename, $buf) = @_;
5301 my $fh = IO
::File-
>new($filename, "w");
5302 return undef if !$fh;
5304 my $res = print $fh $buf;
5311 sub pci_device_info
{
5316 return undef if $name !~ m/^([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\.([a-f0-9])$/;
5317 my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4);
5319 my $irq = file_read_firstline
("$pcisysfs/devices/$name/irq");
5320 return undef if !defined($irq) || $irq !~ m/^\d+$/;
5322 my $vendor = file_read_firstline
("$pcisysfs/devices/$name/vendor");
5323 return undef if !defined($vendor) || $vendor !~ s/^0x//;
5325 my $product = file_read_firstline
("$pcisysfs/devices/$name/device");
5326 return undef if !defined($product) || $product !~ s/^0x//;
5331 product
=> $product,
5337 has_fl_reset
=> -f
"$pcisysfs/devices/$name/reset" || 0,
5346 my $name = $dev->{name
};
5348 my $fn = "$pcisysfs/devices/$name/reset";
5350 return file_write
($fn, "1");
5353 sub pci_dev_bind_to_vfio
{
5356 my $name = $dev->{name
};
5358 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5360 if (!-d
$vfio_basedir) {
5361 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5363 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5365 my $testdir = "$vfio_basedir/$name";
5366 return 1 if -d
$testdir;
5368 my $data = "$dev->{vendor} $dev->{product}";
5369 return undef if !file_write
("$vfio_basedir/new_id", $data);
5371 my $fn = "$pcisysfs/devices/$name/driver/unbind";
5372 if (!file_write
($fn, $name)) {
5373 return undef if -f
$fn;
5376 $fn = "$vfio_basedir/bind";
5377 if (! -d
$testdir) {
5378 return undef if !file_write
($fn, $name);
5384 sub pci_dev_group_bind_to_vfio
{
5387 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5389 if (!-d
$vfio_basedir) {
5390 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5392 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5394 # get IOMMU group devices
5395 opendir(my $D, "$pcisysfs/devices/0000:$pciid/iommu_group/devices/") || die "Cannot open iommu_group: $!\n";
5396 my @devs = grep /^0000:/, readdir($D);
5399 foreach my $pciid (@devs) {
5400 $pciid =~ m/^([:\.\da-f]+)$/ or die "PCI ID $pciid not valid!\n";
5402 # pci bridges, switches or root ports are not supported
5403 # they have a pci_bus subdirectory so skip them
5404 next if (-e
"$pcisysfs/devices/$pciid/pci_bus");
5406 my $info = pci_device_info
($1);
5407 pci_dev_bind_to_vfio
($info) || die "Cannot bind $pciid to vfio\n";
5413 # vzdump restore implementaion
5415 sub tar_archive_read_firstfile
{
5416 my $archive = shift;
5418 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5420 # try to detect archive type first
5421 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5422 die "unable to open file '$archive'\n";
5423 my $firstfile = <$fh>;
5427 die "ERROR: archive contaions no data\n" if !$firstfile;
5433 sub tar_restore_cleanup
{
5434 my ($storecfg, $statfile) = @_;
5436 print STDERR
"starting cleanup\n";
5438 if (my $fd = IO
::File-
>new($statfile, "r")) {
5439 while (defined(my $line = <$fd>)) {
5440 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5443 if ($volid =~ m
|^/|) {
5444 unlink $volid || die 'unlink failed\n';
5446 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5448 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5450 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5452 print STDERR
"unable to parse line in statfile - $line";
5459 sub restore_archive
{
5460 my ($archive, $vmid, $user, $opts) = @_;
5462 my $format = $opts->{format
};
5465 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5466 $format = 'tar' if !$format;
5468 } elsif ($archive =~ m/\.tar$/) {
5469 $format = 'tar' if !$format;
5470 } elsif ($archive =~ m/.tar.lzo$/) {
5471 $format = 'tar' if !$format;
5473 } elsif ($archive =~ m/\.vma$/) {
5474 $format = 'vma' if !$format;
5475 } elsif ($archive =~ m/\.vma\.gz$/) {
5476 $format = 'vma' if !$format;
5478 } elsif ($archive =~ m/\.vma\.lzo$/) {
5479 $format = 'vma' if !$format;
5482 $format = 'vma' if !$format; # default
5485 # try to detect archive format
5486 if ($format eq 'tar') {
5487 return restore_tar_archive
($archive, $vmid, $user, $opts);
5489 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5493 sub restore_update_config_line
{
5494 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5496 return if $line =~ m/^\#qmdump\#/;
5497 return if $line =~ m/^\#vzdump\#/;
5498 return if $line =~ m/^lock:/;
5499 return if $line =~ m/^unused\d+:/;
5500 return if $line =~ m/^parent:/;
5501 return if $line =~ m/^template:/; # restored VM is never a template
5503 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5504 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5505 # try to convert old 1.X settings
5506 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5507 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5508 my ($model, $macaddr) = split(/\=/, $devconfig);
5509 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5512 bridge
=> "vmbr$ind",
5513 macaddr
=> $macaddr,
5515 my $netstr = print_net
($net);
5517 print $outfd "net$cookie->{netcount}: $netstr\n";
5518 $cookie->{netcount
}++;
5520 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5521 my ($id, $netstr) = ($1, $2);
5522 my $net = parse_net
($netstr);
5523 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5524 $netstr = print_net
($net);
5525 print $outfd "$id: $netstr\n";
5526 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5529 my $di = parse_drive
($virtdev, $value);
5530 if (defined($di->{backup
}) && !$di->{backup
}) {
5531 print $outfd "#$line";
5532 } elsif ($map->{$virtdev}) {
5533 delete $di->{format
}; # format can change on restore
5534 $di->{file
} = $map->{$virtdev};
5535 $value = print_drive
($vmid, $di);
5536 print $outfd "$virtdev: $value\n";
5540 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5541 my ($uuid, $uuid_str);
5542 UUID
::generate
($uuid);
5543 UUID
::unparse
($uuid, $uuid_str);
5544 my $smbios1 = parse_smbios1
($2);
5545 $smbios1->{uuid
} = $uuid_str;
5546 print $outfd $1.print_smbios1
($smbios1)."\n";
5553 my ($cfg, $vmid) = @_;
5555 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5557 my $volid_hash = {};
5558 foreach my $storeid (keys %$info) {
5559 foreach my $item (@{$info->{$storeid}}) {
5560 next if !($item->{volid
} && $item->{size
});
5561 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5562 $volid_hash->{$item->{volid
}} = $item;
5569 sub is_volume_in_use
{
5570 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5572 my $path = PVE
::Storage
::path
($storecfg, $volid);
5574 my $scan_config = sub {
5575 my ($cref, $snapname) = @_;
5577 foreach my $key (keys %$cref) {
5578 my $value = $cref->{$key};
5579 if (is_valid_drivename
($key)) {
5580 next if $skip_drive && $key eq $skip_drive;
5581 my $drive = parse_drive
($key, $value);
5582 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5583 return 1 if $volid eq $drive->{file
};
5584 if ($drive->{file
} =~ m!^/!) {
5585 return 1 if $drive->{file
} eq $path;
5587 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5589 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5591 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5599 return 1 if &$scan_config($conf);
5603 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5604 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5610 sub update_disksize
{
5611 my ($vmid, $conf, $volid_hash) = @_;
5615 # used and unused disks
5616 my $referenced = {};
5618 # Note: it is allowed to define multiple storages with same path (alias), so
5619 # we need to check both 'volid' and real 'path' (two different volid can point
5620 # to the same path).
5622 my $referencedpath = {};
5625 foreach my $opt (keys %$conf) {
5626 if (is_valid_drivename
($opt)) {
5627 my $drive = parse_drive
($opt, $conf->{$opt});
5628 my $volid = $drive->{file
};
5631 $referenced->{$volid} = 1;
5632 if ($volid_hash->{$volid} &&
5633 (my $path = $volid_hash->{$volid}->{path
})) {
5634 $referencedpath->{$path} = 1;
5637 next if drive_is_cdrom
($drive);
5638 next if !$volid_hash->{$volid};
5640 $drive->{size
} = $volid_hash->{$volid}->{size
};
5641 my $new = print_drive
($vmid, $drive);
5642 if ($new ne $conf->{$opt}) {
5644 $conf->{$opt} = $new;
5649 # remove 'unusedX' entry if volume is used
5650 foreach my $opt (keys %$conf) {
5651 next if $opt !~ m/^unused\d+$/;
5652 my $volid = $conf->{$opt};
5653 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5654 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5656 delete $conf->{$opt};
5659 $referenced->{$volid} = 1;
5660 $referencedpath->{$path} = 1 if $path;
5663 foreach my $volid (sort keys %$volid_hash) {
5664 next if $volid =~ m/vm-$vmid-state-/;
5665 next if $referenced->{$volid};
5666 my $path = $volid_hash->{$volid}->{path
};
5667 next if !$path; # just to be sure
5668 next if $referencedpath->{$path};
5670 PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5671 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
5678 my ($vmid, $nolock) = @_;
5680 my $cfg = PVE
::Storage
::config
();
5682 my $volid_hash = scan_volids
($cfg, $vmid);
5684 my $updatefn = sub {
5687 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5689 PVE
::QemuConfig-
>check_lock($conf);
5692 foreach my $volid (keys %$volid_hash) {
5693 my $info = $volid_hash->{$volid};
5694 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5697 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5699 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes;
5702 if (defined($vmid)) {
5706 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5709 my $vmlist = config_list
();
5710 foreach my $vmid (keys %$vmlist) {
5714 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5720 sub restore_vma_archive
{
5721 my ($archive, $vmid, $user, $opts, $comp) = @_;
5723 my $input = $archive eq '-' ?
"<&STDIN" : undef;
5724 my $readfrom = $archive;
5729 my $qarchive = PVE
::Tools
::shellquote
($archive);
5730 if ($comp eq 'gzip') {
5731 $uncomp = "zcat $qarchive|";
5732 } elsif ($comp eq 'lzop') {
5733 $uncomp = "lzop -d -c $qarchive|";
5735 die "unknown compression method '$comp'\n";
5740 my $tmpdir = "/var/tmp/vzdumptmp$$";
5743 # disable interrupts (always do cleanups)
5747 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
5749 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
5750 POSIX
::mkfifo
($mapfifo, 0600);
5753 my $openfifo = sub {
5754 open($fifofh, '>', $mapfifo) || die $!;
5757 my $cmd = "${uncomp}vma extract -v -r $mapfifo $readfrom $tmpdir";
5764 my $rpcenv = PVE
::RPCEnvironment
::get
();
5766 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5767 my $tmpfn = "$conffile.$$.tmp";
5769 # Note: $oldconf is undef if VM does not exists
5770 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
5771 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
5773 my $print_devmap = sub {
5774 my $virtdev_hash = {};
5776 my $cfgfn = "$tmpdir/qemu-server.conf";
5778 # we can read the config - that is already extracted
5779 my $fh = IO
::File-
>new($cfgfn, "r") ||
5780 "unable to read qemu-server.conf - $!\n";
5782 my $fwcfgfn = "$tmpdir/qemu-server.fw";
5784 my $pve_firewall_dir = '/etc/pve/firewall';
5785 mkdir $pve_firewall_dir; # make sure the dir exists
5786 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
5789 while (defined(my $line = <$fh>)) {
5790 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
5791 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
5792 die "archive does not contain data for drive '$virtdev'\n"
5793 if !$devinfo->{$devname};
5794 if (defined($opts->{storage
})) {
5795 $storeid = $opts->{storage
} || 'local';
5796 } elsif (!$storeid) {
5799 $format = 'raw' if !$format;
5800 $devinfo->{$devname}->{devname
} = $devname;
5801 $devinfo->{$devname}->{virtdev
} = $virtdev;
5802 $devinfo->{$devname}->{format
} = $format;
5803 $devinfo->{$devname}->{storeid
} = $storeid;
5805 # check permission on storage
5806 my $pool = $opts->{pool
}; # todo: do we need that?
5807 if ($user ne 'root@pam') {
5808 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
5811 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
5815 foreach my $devname (keys %$devinfo) {
5816 die "found no device mapping information for device '$devname'\n"
5817 if !$devinfo->{$devname}->{virtdev
};
5820 my $cfg = PVE
::Storage
::config
();
5822 # create empty/temp config
5824 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
5825 foreach_drive
($oldconf, sub {
5826 my ($ds, $drive) = @_;
5828 return if drive_is_cdrom
($drive);
5830 my $volid = $drive->{file
};
5832 return if !$volid || $volid =~ m
|^/|;
5834 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
5835 return if !$path || !$owner || ($owner != $vmid);
5837 # Note: only delete disk we want to restore
5838 # other volumes will become unused
5839 if ($virtdev_hash->{$ds}) {
5840 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
5847 # delete vmstate files
5848 # since after the restore we have no snapshots anymore
5849 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
5850 my $snap = $oldconf->{snapshots
}->{$snapname};
5851 if ($snap->{vmstate
}) {
5852 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
5861 foreach my $virtdev (sort keys %$virtdev_hash) {
5862 my $d = $virtdev_hash->{$virtdev};
5863 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
5864 my $scfg = PVE
::Storage
::storage_config
($cfg, $d->{storeid
});
5866 # test if requested format is supported
5867 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $d->{storeid
});
5868 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
5869 $d->{format
} = $defFormat if !$supported;
5871 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $d->{storeid
}, $vmid,
5872 $d->{format
}, undef, $alloc_size);
5873 print STDERR
"new volume ID is '$volid'\n";
5874 $d->{volid
} = $volid;
5875 my $path = PVE
::Storage
::path
($cfg, $volid);
5877 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
5879 my $write_zeros = 1;
5880 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
5884 print $fifofh "format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
5886 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
5887 $map->{$virtdev} = $volid;
5890 $fh->seek(0, 0) || die "seek failed - $!\n";
5892 my $outfd = new IO
::File
($tmpfn, "w") ||
5893 die "unable to write config for VM $vmid\n";
5895 my $cookie = { netcount
=> 0 };
5896 while (defined(my $line = <$fh>)) {
5897 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
5910 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
5911 local $SIG{ALRM
} = sub { die "got timeout\n"; };
5913 $oldtimeout = alarm($timeout);
5920 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
5921 my ($dev_id, $size, $devname) = ($1, $2, $3);
5922 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
5923 } elsif ($line =~ m/^CTIME: /) {
5924 # we correctly received the vma config, so we can disable
5925 # the timeout now for disk allocation (set to 10 minutes, so
5926 # that we always timeout if something goes wrong)
5929 print $fifofh "done\n";
5930 my $tmp = $oldtimeout || 0;
5931 $oldtimeout = undef;
5937 print "restore vma archive: $cmd\n";
5938 run_command
($cmd, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
5942 alarm($oldtimeout) if $oldtimeout;
5945 foreach my $devname (keys %$devinfo) {
5946 my $volid = $devinfo->{$devname}->{volid
};
5947 push @$vollist, $volid if $volid;
5950 my $cfg = PVE
::Storage
::config
();
5951 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
5959 foreach my $devname (keys %$devinfo) {
5960 my $volid = $devinfo->{$devname}->{volid
};
5963 if ($volid =~ m
|^/|) {
5964 unlink $volid || die 'unlink failed\n';
5966 PVE
::Storage
::vdisk_free
($cfg, $volid);
5968 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5970 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5977 rename($tmpfn, $conffile) ||
5978 die "unable to commit configuration file '$conffile'\n";
5980 PVE
::Cluster
::cfs_update
(); # make sure we read new file
5982 eval { rescan
($vmid, 1); };
5986 sub restore_tar_archive
{
5987 my ($archive, $vmid, $user, $opts) = @_;
5989 if ($archive ne '-') {
5990 my $firstfile = tar_archive_read_firstfile
($archive);
5991 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
5992 if $firstfile ne 'qemu-server.conf';
5995 my $storecfg = PVE
::Storage
::config
();
5997 # destroy existing data - keep empty config
5998 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
5999 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
6001 my $tocmd = "/usr/lib/qemu-server/qmextract";
6003 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
6004 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
6005 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6006 $tocmd .= ' --info' if $opts->{info
};
6008 # tar option "xf" does not autodetect compression when read from STDIN,
6009 # so we pipe to zcat
6010 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6011 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6013 my $tmpdir = "/var/tmp/vzdumptmp$$";
6016 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6017 local $ENV{VZDUMP_VMID
} = $vmid;
6018 local $ENV{VZDUMP_USER
} = $user;
6020 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6021 my $tmpfn = "$conffile.$$.tmp";
6023 # disable interrupts (always do cleanups)
6027 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6035 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6037 if ($archive eq '-') {
6038 print "extracting archive from STDIN\n";
6039 run_command
($cmd, input
=> "<&STDIN");
6041 print "extracting archive '$archive'\n";
6045 return if $opts->{info
};
6049 my $statfile = "$tmpdir/qmrestore.stat";
6050 if (my $fd = IO
::File-
>new($statfile, "r")) {
6051 while (defined (my $line = <$fd>)) {
6052 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6053 $map->{$1} = $2 if $1;
6055 print STDERR
"unable to parse line in statfile - $line\n";
6061 my $confsrc = "$tmpdir/qemu-server.conf";
6063 my $srcfd = new IO
::File
($confsrc, "r") ||
6064 die "unable to open file '$confsrc'\n";
6066 my $outfd = new IO
::File
($tmpfn, "w") ||
6067 die "unable to write config for VM $vmid\n";
6069 my $cookie = { netcount
=> 0 };
6070 while (defined (my $line = <$srcfd>)) {
6071 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6083 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6090 rename $tmpfn, $conffile ||
6091 die "unable to commit configuration file '$conffile'\n";
6093 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6095 eval { rescan
($vmid, 1); };
6099 sub foreach_storage_used_by_vm
{
6100 my ($conf, $func) = @_;
6104 foreach_drive
($conf, sub {
6105 my ($ds, $drive) = @_;
6106 return if drive_is_cdrom
($drive);
6108 my $volid = $drive->{file
};
6110 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6111 $sidhash->{$sid} = $sid if $sid;
6114 foreach my $sid (sort keys %$sidhash) {
6119 sub do_snapshots_with_qemu
{
6120 my ($storecfg, $volid) = @_;
6122 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6124 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
6125 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
6129 if ($volid =~ m/\.(qcow2|qed)$/){
6136 sub qga_check_running
{
6139 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6141 warn "Qemu Guest Agent is not running - $@";
6147 sub template_create
{
6148 my ($vmid, $conf, $disk) = @_;
6150 my $storecfg = PVE
::Storage
::config
();
6152 foreach_drive
($conf, sub {
6153 my ($ds, $drive) = @_;
6155 return if drive_is_cdrom
($drive);
6156 return if $disk && $ds ne $disk;
6158 my $volid = $drive->{file
};
6159 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6161 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6162 $drive->{file
} = $voliddst;
6163 $conf->{$ds} = print_drive
($vmid, $drive);
6164 PVE
::QemuConfig-
>write_config($vmid, $conf);
6168 sub qemu_img_convert
{
6169 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6171 my $storecfg = PVE
::Storage
::config
();
6172 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6173 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6175 if ($src_storeid && $dst_storeid) {
6177 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6179 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6180 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6182 my $src_format = qemu_img_format
($src_scfg, $src_volname);
6183 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6185 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6186 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6189 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6190 push @$cmd, '-s', $snapname if($snapname && $src_format eq "qcow2");
6191 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
6192 if ($is_zero_initialized) {
6193 push @$cmd, "zeroinit:$dst_path";
6195 push @$cmd, $dst_path;
6200 if($line =~ m/\((\S+)\/100\
%\)/){
6202 my $transferred = int($size * $percent / 100);
6203 my $remaining = $size - $transferred;
6205 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6210 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6212 die "copy failed: $err" if $err;
6216 sub qemu_img_format
{
6217 my ($scfg, $volname) = @_;
6219 if ($scfg->{path
} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
6226 sub qemu_drive_mirror
{
6227 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga) = @_;
6229 $jobs = {} if !$jobs;
6233 $jobs->{"drive-$drive"} = {};
6235 if ($dst_volid =~ /^nbd:/) {
6236 $qemu_target = $dst_volid;
6239 my $storecfg = PVE
::Storage
::config
();
6240 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6242 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6244 $format = qemu_img_format
($dst_scfg, $dst_volname);
6246 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6248 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6251 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6252 $opts->{format
} = $format if $format;
6254 print "drive mirror is starting for drive-$drive\n";
6256 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
6259 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6260 die "mirroring error: $err";
6263 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
6266 sub qemu_drive_mirror_monitor
{
6267 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
6270 my $err_complete = 0;
6273 die "storage migration timed out\n" if $err_complete > 300;
6275 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6277 my $running_mirror_jobs = {};
6278 foreach my $stat (@$stats) {
6279 next if $stat->{type
} ne 'mirror';
6280 $running_mirror_jobs->{$stat->{device
}} = $stat;
6283 my $readycounter = 0;
6285 foreach my $job (keys %$jobs) {
6287 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6288 print "$job : finished\n";
6289 delete $jobs->{$job};
6293 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6295 my $busy = $running_mirror_jobs->{$job}->{busy
};
6296 my $ready = $running_mirror_jobs->{$job}->{ready
};
6297 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6298 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6299 my $remaining = $total - $transferred;
6300 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6302 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6305 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6308 last if scalar(keys %$jobs) == 0;
6310 if ($readycounter == scalar(keys %$jobs)) {
6311 print "all mirroring jobs are ready \n";
6312 last if $skipcomplete; #do the complete later
6314 if ($vmiddst && $vmiddst != $vmid) {
6315 my $agent_running = $qga && qga_check_running
($vmid);
6316 if ($agent_running) {
6317 print "freeze filesystem\n";
6318 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6320 print "suspend vm\n";
6321 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6324 # if we clone a disk for a new target vm, we don't switch the disk
6325 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6327 if ($agent_running) {
6328 print "unfreeze filesystem\n";
6329 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6331 print "resume vm\n";
6332 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6338 foreach my $job (keys %$jobs) {
6339 # try to switch the disk if source and destination are on the same guest
6340 print "$job: Completing block job...\n";
6342 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6343 if ($@ =~ m/cannot be completed/) {
6344 print "$job: Block job cannot be completed, try again.\n";
6347 print "$job: Completed successfully.\n";
6348 $jobs->{$job}->{complete
} = 1;
6359 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6360 die "mirroring error: $err";
6365 sub qemu_blockjobs_cancel
{
6366 my ($vmid, $jobs) = @_;
6368 foreach my $job (keys %$jobs) {
6369 print "$job: Cancelling block job\n";
6370 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6371 $jobs->{$job}->{cancel
} = 1;
6375 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6377 my $running_jobs = {};
6378 foreach my $stat (@$stats) {
6379 $running_jobs->{$stat->{device
}} = $stat;
6382 foreach my $job (keys %$jobs) {
6384 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6385 print "$job: Done.\n";
6386 delete $jobs->{$job};
6390 last if scalar(keys %$jobs) == 0;
6397 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6398 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;
6403 print "create linked clone of drive $drivename ($drive->{file})\n";
6404 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6405 push @$newvollist, $newvolid;
6408 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6409 $storeid = $storage if $storage;
6411 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
6412 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6414 print "create full clone of drive $drivename ($drive->{file})\n";
6416 if (drive_is_cloudinit
($drive)) {
6417 $name = "vm-$newvmid-cloudinit";
6418 # cloudinit only supports raw and qcow2 atm:
6419 if ($dst_format eq 'qcow2') {
6421 } elsif ($dst_format ne 'raw') {
6422 die "clone: unhandled format for cloudinit image\n";
6425 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
6426 push @$newvollist, $newvolid;
6428 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6430 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6431 if (!$running || $snapname) {
6432 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6435 my $kvmver = get_running_qemu_version
($vmid);
6436 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
6437 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6438 if $drive->{iothread
};
6441 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga);
6445 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6448 $disk->{format
} = undef;
6449 $disk->{file
} = $newvolid;
6450 $disk->{size
} = $size;
6455 # this only works if VM is running
6456 sub get_current_qemu_machine
{
6459 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
6460 my $res = vm_qmp_command
($vmid, $cmd);
6462 my ($current, $default);
6463 foreach my $e (@$res) {
6464 $default = $e->{name
} if $e->{'is-default'};
6465 $current = $e->{name
} if $e->{'is-current'};
6468 # fallback to the default machine if current is not supported by qemu
6469 return $current || $default || 'pc';
6472 sub get_running_qemu_version
{
6474 my $cmd = { execute
=> 'query-version', arguments
=> {} };
6475 my $res = vm_qmp_command
($vmid, $cmd);
6476 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6479 sub qemu_machine_feature_enabled
{
6480 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6485 if ($machine && $machine =~ m/^(pc(-i440fx|-q35)?-(\d+)\.(\d+))/) {
6487 $current_major = $3;
6488 $current_minor = $4;
6490 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6492 $current_major = $1;
6493 $current_minor = $2;
6496 return 1 if $current_major >= $version_major && $current_minor >= $version_minor;
6501 sub qemu_machine_pxe
{
6502 my ($vmid, $conf, $machine) = @_;
6504 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6506 foreach my $opt (keys %$conf) {
6507 next if $opt !~ m/^net(\d+)$/;
6508 my $net = PVE
::QemuServer
::parse_net
($conf->{$opt});
6510 my $romfile = PVE
::QemuServer
::vm_mon_cmd_nocheck
($vmid, 'qom-get', path
=> $opt, property
=> 'romfile');
6511 return $machine.".pxe" if $romfile =~ m/pxe/;
6518 sub qemu_use_old_bios_files
{
6519 my ($machine_type) = @_;
6521 return if !$machine_type;
6523 my $use_old_bios_files = undef;
6525 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6527 $use_old_bios_files = 1;
6529 my $kvmver = kvm_user_version
();
6530 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6531 # load new efi bios files on migration. So this hack is required to allow
6532 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6533 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6534 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6537 return ($use_old_bios_files, $machine_type);
6540 sub create_efidisk
{
6541 my ($storecfg, $storeid, $vmid, $fmt) = @_;
6543 die "EFI vars default image not found\n" if ! -f
$OVMF_VARS;
6545 my $vars_size = PVE
::Tools
::convert_size
(-s
$OVMF_VARS, 'b' => 'kb');
6546 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6547 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6549 my $path = PVE
::Storage
::path
($storecfg, $volid);
6551 run_command
(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $OVMF_VARS, $path]);
6553 die "Copying EFI vars image failed: $@" if $@;
6555 return ($volid, $vars_size);
6562 dir_glob_foreach
("$pcisysfs/devices", '[a-f0-9]{4}:([a-f0-9]{2}:[a-f0-9]{2})\.([0-9])', sub {
6563 my (undef, $id, $function) = @_;
6564 my $res = { id
=> $id, function
=> $function};
6565 push @{$devices->{$id}}, $res;
6568 # Entries should be sorted by functions.
6569 foreach my $id (keys %$devices) {
6570 my $dev = $devices->{$id};
6571 $devices->{$id} = [ sort { $a->{function
} <=> $b->{function
} } @$dev ];
6577 sub vm_iothreads_list
{
6580 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6583 foreach my $iothread (@$res) {
6584 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6591 my ($conf, $drive) = @_;
6595 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
6597 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6603 my $controller = int($drive->{index} / $maxdev);
6604 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6606 return ($maxdev, $controller, $controller_prefix);
6609 sub add_hyperv_enlightenments
{
6610 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough) = @_;
6612 return if $winversion < 6;
6613 return if $bios && $bios eq 'ovmf' && $winversion < 8;
6615 push @$cpuFlags , 'hv_vendor_id=proxmox' if $gpu_passthrough;
6617 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
6618 push @$cpuFlags , 'hv_spinlocks=0x1fff';
6619 push @$cpuFlags , 'hv_vapic';
6620 push @$cpuFlags , 'hv_time';
6622 push @$cpuFlags , 'hv_spinlocks=0xffff';
6625 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
6626 push @$cpuFlags , 'hv_reset';
6627 push @$cpuFlags , 'hv_vpindex';
6628 push @$cpuFlags , 'hv_runtime';
6631 if ($winversion >= 7) {
6632 push @$cpuFlags , 'hv_relaxed';
6636 sub windows_version
{
6639 return 0 if !$ostype;
6643 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6645 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6647 } elsif ($ostype =~ m/^win(\d+)$/) {
6654 sub resolve_dst_disk_format
{
6655 my ($storecfg, $storeid, $src_volname, $format) = @_;
6656 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6659 # if no target format is specified, use the source disk format as hint
6661 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6662 $format = qemu_img_format
($scfg, $src_volname);
6668 # test if requested format is supported - else use default
6669 my $supported = grep { $_ eq $format } @$validFormats;
6670 $format = $defFormat if !$supported;
6674 sub resolve_first_disk
{
6676 my @disks = PVE
::QemuServer
::valid_drive_names
();
6678 foreach my $ds (reverse @disks) {
6679 next if !$conf->{$ds};
6680 my $disk = PVE
::QemuServer
::parse_drive
($ds, $conf->{$ds});
6681 next if PVE
::QemuServer
::drive_is_cdrom
($disk);
6687 sub generate_smbios1_uuid
{
6688 my ($uuid, $uuid_str);
6689 UUID
::generate
($uuid);
6690 UUID
::unparse
($uuid, $uuid_str);
6691 return "uuid=$uuid_str";
6694 # bash completion helper
6696 sub complete_backup_archives
{
6697 my ($cmdname, $pname, $cvalue) = @_;
6699 my $cfg = PVE
::Storage
::config
();
6703 if ($cvalue =~ m/^([^:]+):/) {
6707 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
6710 foreach my $id (keys %$data) {
6711 foreach my $item (@{$data->{$id}}) {
6712 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
6713 push @$res, $item->{volid
} if defined($item->{volid
});
6720 my $complete_vmid_full = sub {
6723 my $idlist = vmstatus
();
6727 foreach my $id (keys %$idlist) {
6728 my $d = $idlist->{$id};
6729 if (defined($running)) {
6730 next if $d->{template
};
6731 next if $running && $d->{status
} ne 'running';
6732 next if !$running && $d->{status
} eq 'running';
6741 return &$complete_vmid_full();
6744 sub complete_vmid_stopped
{
6745 return &$complete_vmid_full(0);
6748 sub complete_vmid_running
{
6749 return &$complete_vmid_full(1);
6752 sub complete_storage
{
6754 my $cfg = PVE
::Storage
::config
();
6755 my $ids = $cfg->{ids
};
6758 foreach my $sid (keys %$ids) {
6759 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
6760 next if !$ids->{$sid}->{content
}->{images
};