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. '
558 . 'Also note that older cloud-init versions do not support hashed passwords.',
563 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.",
567 type
=> 'string', format
=> 'address-list',
568 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.",
573 format
=> 'urlencoded',
574 description
=> "cloud-init : Setup public SSH keys (one key per line, " .
579 # what about other qemu settings ?
581 #machine => 'string',
594 ##soundhw => 'string',
596 while (my ($k, $v) = each %$confdesc) {
597 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
600 my $MAX_IDE_DISKS = 4;
601 my $MAX_SCSI_DISKS = 14;
602 my $MAX_VIRTIO_DISKS = 16;
603 my $MAX_SATA_DISKS = 6;
604 my $MAX_USB_DEVICES = 5;
606 my $MAX_UNUSED_DISKS = 8;
607 my $MAX_HOSTPCI_DEVICES = 4;
608 my $MAX_SERIAL_PORTS = 4;
609 my $MAX_PARALLEL_PORTS = 3;
615 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
616 description
=> "CPUs accessing this NUMA node.",
617 format_description
=> "id[-id];...",
621 description
=> "Amount of memory this NUMA node provides.",
626 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
627 description
=> "Host NUMA nodes to use.",
628 format_description
=> "id[-id];...",
633 enum
=> [qw(preferred bind interleave)],
634 description
=> "NUMA allocation policy.",
638 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
641 type
=> 'string', format
=> $numa_fmt,
642 description
=> "NUMA topology.",
644 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
646 for (my $i = 0; $i < $MAX_NUMA; $i++) {
647 $confdesc->{"numa$i"} = $numadesc;
650 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
651 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
652 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
653 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
655 my $net_fmt_bridge_descr = <<__EOD__;
656 Bridge to attach the network device to. The Proxmox VE standard bridge
659 If you do not specify a bridge, we create a kvm user (NATed) network
660 device, which provides DHCP and DNS services. The following addresses
667 The DHCP server assign addresses to the guest starting from 10.0.2.15.
673 pattern
=> qr/[0-9a-f]{2}(?::[0-9a-f]{2}){5}/i,
674 description
=> "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
675 format_description
=> "XX:XX:XX:XX:XX:XX",
680 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'.",
681 enum
=> $nic_model_list,
684 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
687 description
=> $net_fmt_bridge_descr,
688 format_description
=> 'bridge',
693 minimum
=> 0, maximum
=> 16,
694 description
=> 'Number of packet queues to be used on the device.',
700 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
705 minimum
=> 1, maximum
=> 4094,
706 description
=> 'VLAN tag to apply to packets on this interface.',
711 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
712 description
=> 'VLAN trunks to pass through this interface.',
713 format_description
=> 'vlanid[;vlanid...]',
718 description
=> 'Whether this interface should be protected by the firewall.',
723 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
730 type
=> 'string', format
=> $net_fmt,
731 description
=> "Specify network devices.",
734 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
739 format
=> 'pve-ipv4-config',
740 format_description
=> 'IPv4Format/CIDR',
741 description
=> 'IPv4 address in CIDR format.',
748 format_description
=> 'GatewayIPv4',
749 description
=> 'Default gateway for IPv4 traffic.',
755 format
=> 'pve-ipv6-config',
756 format_description
=> 'IPv6Format/CIDR',
757 description
=> 'IPv6 address in CIDR format.',
764 format_description
=> 'GatewayIPv6',
765 description
=> 'Default gateway for IPv6 traffic.',
770 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
773 type
=> 'string', format
=> 'pve-qm-ipconfig',
774 description
=> <<'EODESCR',
775 cloud-init: Specify IP addresses and gateways for the corresponding interface.
777 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
779 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided.
780 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration.
782 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4.
785 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
787 for (my $i = 0; $i < $MAX_NETS; $i++) {
788 $confdesc->{"net$i"} = $netdesc;
789 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
792 foreach my $key (keys %$confdesc_cloudinit) {
793 $confdesc->{$key} = $confdesc_cloudinit->{$key};
796 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
797 sub verify_volume_id_or_qm_path
{
798 my ($volid, $noerr) = @_;
800 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
804 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
805 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
807 return undef if $noerr;
815 my %drivedesc_base = (
816 volume
=> { alias
=> 'file' },
819 format
=> 'pve-volume-id-or-qm-path',
821 format_description
=> 'volume',
822 description
=> "The drive's backing volume.",
826 enum
=> [qw(cdrom disk)],
827 description
=> "The drive's media type.",
833 description
=> "Force the drive's physical geometry to have a specific cylinder count.",
838 description
=> "Force the drive's physical geometry to have a specific head count.",
843 description
=> "Force the drive's physical geometry to have a specific sector count.",
848 enum
=> [qw(none lba auto)],
849 description
=> "Force disk geometry bios translation mode.",
854 description
=> "Controls qemu's snapshot mode feature."
855 . " If activated, changes made to the disk are temporary and will"
856 . " be discarded when the VM is shutdown.",
861 enum
=> [qw(none writethrough writeback unsafe directsync)],
862 description
=> "The drive's cache mode",
865 format
=> get_standard_option
('pve-qm-image-format'),
868 format
=> 'disk-size',
869 format_description
=> 'DiskSize',
870 description
=> "Disk size. This is purely informational and has no effect.",
875 description
=> "Whether the drive should be included when making backups.",
880 description
=> 'Whether the drive should considered for replication jobs.',
886 enum
=> [qw(ignore report stop)],
887 description
=> 'Read error action.',
892 enum
=> [qw(enospc ignore report stop)],
893 description
=> 'Write error action.',
898 enum
=> [qw(native threads)],
899 description
=> 'AIO type to use.',
904 enum
=> [qw(ignore on)],
905 description
=> 'Controls whether to pass discard/trim requests to the underlying storage.',
910 description
=> 'Controls whether to detect and try to optimize writes of zeroes.',
915 format
=> 'urlencoded',
916 format_description
=> 'serial',
917 maxLength
=> 20*3, # *3 since it's %xx url enoded
918 description
=> "The drive's reported serial number, url-encoded, up to 20 bytes long.",
923 description
=> 'Mark this locally-managed volume as available on all nodes',
924 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!",
930 my %iothread_fmt = ( iothread
=> {
932 description
=> "Whether to use iothreads for this drive",
939 format
=> 'urlencoded',
940 format_description
=> 'model',
941 maxLength
=> 40*3, # *3 since it's %xx url enoded
942 description
=> "The drive's reported model name, url-encoded, up to 40 bytes long.",
950 description
=> "Number of queues.",
956 my %scsiblock_fmt = (
959 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",
965 my $add_throttle_desc = sub {
966 my ($key, $type, $what, $unit, $longunit, $minimum) = @_;
969 format_description
=> $unit,
970 description
=> "Maximum $what in $longunit.",
973 $d->{minimum
} = $minimum if defined($minimum);
974 $drivedesc_base{$key} = $d;
976 # throughput: (leaky bucket)
977 $add_throttle_desc->('bps', 'integer', 'r/w speed', 'bps', 'bytes per second');
978 $add_throttle_desc->('bps_rd', 'integer', 'read speed', 'bps', 'bytes per second');
979 $add_throttle_desc->('bps_wr', 'integer', 'write speed', 'bps', 'bytes per second');
980 $add_throttle_desc->('mbps', 'number', 'r/w speed', 'mbps', 'megabytes per second');
981 $add_throttle_desc->('mbps_rd', 'number', 'read speed', 'mbps', 'megabytes per second');
982 $add_throttle_desc->('mbps_wr', 'number', 'write speed', 'mbps', 'megabytes per second');
983 $add_throttle_desc->('iops', 'integer', 'r/w I/O', 'iops', 'operations per second');
984 $add_throttle_desc->('iops_rd', 'integer', 'read I/O', 'iops', 'operations per second');
985 $add_throttle_desc->('iops_wr', 'integer', 'write I/O', 'iops', 'operations per second');
987 # pools: (pool of IO before throttling starts taking effect)
988 $add_throttle_desc->('mbps_max', 'number', 'unthrottled r/w pool', 'mbps', 'megabytes per second');
989 $add_throttle_desc->('mbps_rd_max', 'number', 'unthrottled read pool', 'mbps', 'megabytes per second');
990 $add_throttle_desc->('mbps_wr_max', 'number', 'unthrottled write pool', 'mbps', 'megabytes per second');
991 $add_throttle_desc->('iops_max', 'integer', 'unthrottled r/w I/O pool', 'iops', 'operations per second');
992 $add_throttle_desc->('iops_rd_max', 'integer', 'unthrottled read I/O pool', 'iops', 'operations per second');
993 $add_throttle_desc->('iops_wr_max', 'integer', 'unthrottled write I/O pool', 'iops', 'operations per second');
996 $add_throttle_desc->('bps_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
997 $add_throttle_desc->('bps_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
998 $add_throttle_desc->('bps_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
999 $add_throttle_desc->('iops_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
1000 $add_throttle_desc->('iops_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
1001 $add_throttle_desc->('iops_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1004 $drivedesc_base{'bps_rd_length'} = { alias
=> 'bps_rd_max_length' };
1005 $drivedesc_base{'bps_wr_length'} = { alias
=> 'bps_wr_max_length' };
1006 $drivedesc_base{'iops_rd_length'} = { alias
=> 'iops_rd_max_length' };
1007 $drivedesc_base{'iops_wr_length'} = { alias
=> 'iops_wr_max_length' };
1013 PVE
::JSONSchema
::register_format
("pve-qm-ide", $ide_fmt);
1017 type
=> 'string', format
=> $ide_fmt,
1018 description
=> "Use volume as IDE hard disk or CD-ROM (n is 0 to " .($MAX_IDE_DISKS -1) . ").",
1020 PVE
::JSONSchema
::register_standard_option
("pve-qm-ide", $idedesc);
1030 type
=> 'string', format
=> $scsi_fmt,
1031 description
=> "Use volume as SCSI hard disk or CD-ROM (n is 0 to " . ($MAX_SCSI_DISKS - 1) . ").",
1033 PVE
::JSONSchema
::register_standard_option
("pve-qm-scsi", $scsidesc);
1040 type
=> 'string', format
=> $sata_fmt,
1041 description
=> "Use volume as SATA hard disk or CD-ROM (n is 0 to " . ($MAX_SATA_DISKS - 1). ").",
1043 PVE
::JSONSchema
::register_standard_option
("pve-qm-sata", $satadesc);
1051 type
=> 'string', format
=> $virtio_fmt,
1052 description
=> "Use volume as VIRTIO hard disk (n is 0 to " . ($MAX_VIRTIO_DISKS - 1) . ").",
1054 PVE
::JSONSchema
::register_standard_option
("pve-qm-virtio", $virtiodesc);
1056 my $alldrive_fmt = {
1065 volume
=> { alias
=> 'file' },
1068 format
=> 'pve-volume-id-or-qm-path',
1070 format_description
=> 'volume',
1071 description
=> "The drive's backing volume.",
1073 format
=> get_standard_option
('pve-qm-image-format'),
1076 format
=> 'disk-size',
1077 format_description
=> 'DiskSize',
1078 description
=> "Disk size. This is purely informational and has no effect.",
1083 my $efidisk_desc = {
1085 type
=> 'string', format
=> $efidisk_fmt,
1086 description
=> "Configure a Disk for storing EFI vars",
1089 PVE
::JSONSchema
::register_standard_option
("pve-qm-efidisk", $efidisk_desc);
1094 type
=> 'string', format
=> 'pve-qm-usb-device',
1095 format_description
=> 'HOSTUSBDEVICE|spice',
1096 description
=> <<EODESCR,
1097 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1099 'bus-port(.port)*' (decimal numbers) or
1100 'vendor_id:product_id' (hexadeciaml numbers) or
1103 You can use the 'lsusb -t' command to list existing usb devices.
1105 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1107 The value 'spice' can be used to add a usb redirection devices for spice.
1113 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).",
1120 type
=> 'string', format
=> $usb_fmt,
1121 description
=> "Configure an USB device (n is 0 to 4).",
1123 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
1125 # NOTE: the match-groups of this regex are used in parse_hostpci
1126 my $PCIRE = qr/([a-f0-9]{2}:[a-f0-9]{2})(?:\.([a-f0-9]))?/;
1131 pattern
=> qr/$PCIRE(;$PCIRE)*/,
1132 format_description
=> 'HOSTPCIID[;HOSTPCIID2...]',
1133 description
=> <<EODESCR,
1134 Host PCI device pass through. The PCI ID of a host's PCI device or a list
1135 of PCI virtual functions of the host. HOSTPCIID syntax is:
1137 'bus:dev.func' (hexadecimal numbers)
1139 You can us the 'lspci' command to list existing PCI devices.
1144 description
=> "Specify whether or not the device's ROM will be visible in the guest's memory map.",
1150 pattern
=> '[^,;]+',
1151 format_description
=> 'string',
1152 description
=> "Custom pci device rom filename (must be located in /usr/share/kvm/).",
1157 description
=> "Choose the PCI-express bus (needs the 'q35' machine model).",
1163 description
=> "Enable vfio-vga device support.",
1168 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', $hostpci_fmt);
1172 type
=> 'string', format
=> 'pve-qm-hostpci',
1173 description
=> "Map host PCI devices into guest.",
1174 verbose_description
=> <<EODESCR,
1175 Map host PCI devices into guest.
1177 NOTE: This option allows direct access to host hardware. So it is no longer
1178 possible to migrate such machines - use with special care.
1180 CAUTION: Experimental! User reported problems with this option.
1183 PVE
::JSONSchema
::register_standard_option
("pve-qm-hostpci", $hostpcidesc);
1188 pattern
=> '(/dev/.+|socket)',
1189 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1190 verbose_description
=> <<EODESCR,
1191 Create a serial device inside the VM (n is 0 to 3), and pass through a
1192 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1193 host side (use 'qm terminal' to open a terminal connection).
1195 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
1197 CAUTION: Experimental! User reported problems with this option.
1204 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1205 description
=> "Map host parallel devices (n is 0 to 2).",
1206 verbose_description
=> <<EODESCR,
1207 Map host parallel devices (n is 0 to 2).
1209 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1211 CAUTION: Experimental! User reported problems with this option.
1215 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1216 $confdesc->{"parallel$i"} = $paralleldesc;
1219 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1220 $confdesc->{"serial$i"} = $serialdesc;
1223 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
1224 $confdesc->{"hostpci$i"} = $hostpcidesc;
1227 for (my $i = 0; $i < $MAX_IDE_DISKS; $i++) {
1228 $drivename_hash->{"ide$i"} = 1;
1229 $confdesc->{"ide$i"} = $idedesc;
1232 for (my $i = 0; $i < $MAX_SATA_DISKS; $i++) {
1233 $drivename_hash->{"sata$i"} = 1;
1234 $confdesc->{"sata$i"} = $satadesc;
1237 for (my $i = 0; $i < $MAX_SCSI_DISKS; $i++) {
1238 $drivename_hash->{"scsi$i"} = 1;
1239 $confdesc->{"scsi$i"} = $scsidesc ;
1242 for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++) {
1243 $drivename_hash->{"virtio$i"} = 1;
1244 $confdesc->{"virtio$i"} = $virtiodesc;
1247 $drivename_hash->{efidisk0
} = 1;
1248 $confdesc->{efidisk0
} = $efidisk_desc;
1250 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1251 $confdesc->{"usb$i"} = $usbdesc;
1256 type
=> 'string', format
=> 'pve-volume-id',
1257 description
=> "Reference to unused volumes. This is used internally, and should not be modified manually.",
1260 for (my $i = 0; $i < $MAX_UNUSED_DISKS; $i++) {
1261 $confdesc->{"unused$i"} = $unuseddesc;
1264 my $kvm_api_version = 0;
1268 return $kvm_api_version if $kvm_api_version;
1270 my $fh = IO
::File-
>new("</dev/kvm") ||
1273 if (my $v = $fh->ioctl(KVM_GET_API_VERSION
(), 0)) {
1274 $kvm_api_version = $v;
1279 return $kvm_api_version;
1282 my $kvm_user_version;
1284 sub kvm_user_version
{
1286 return $kvm_user_version if $kvm_user_version;
1288 $kvm_user_version = 'unknown';
1292 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1293 $kvm_user_version = $2;
1297 eval { run_command
("kvm -version", outfunc
=> $code); };
1300 return $kvm_user_version;
1304 my $kernel_has_vhost_net = -c
'/dev/vhost-net';
1306 sub valid_drive_names
{
1307 # order is important - used to autoselect boot disk
1308 return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
1309 (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
1310 (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))),
1311 (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))),
1315 sub is_valid_drivename
{
1318 return defined($drivename_hash->{$dev});
1323 return defined($confdesc->{$key});
1327 return $nic_model_list;
1330 sub os_list_description
{
1334 wxp
=> 'Windows XP',
1335 w2k
=> 'Windows 2000',
1336 w2k3
=>, 'Windows 2003',
1337 w2k8
=> 'Windows 2008',
1338 wvista
=> 'Windows Vista',
1339 win7
=> 'Windows 7',
1340 win8
=> 'Windows 8/2012',
1341 win10
=> 'Windows 10/2016',
1349 sub get_cdrom_path
{
1351 return $cdrom_path if $cdrom_path;
1353 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1354 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1355 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1359 my ($storecfg, $vmid, $cdrom) = @_;
1361 if ($cdrom eq 'cdrom') {
1362 return get_cdrom_path
();
1363 } elsif ($cdrom eq 'none') {
1365 } elsif ($cdrom =~ m
|^/|) {
1368 return PVE
::Storage
::path
($storecfg, $cdrom);
1372 # try to convert old style file names to volume IDs
1373 sub filename_to_volume_id
{
1374 my ($vmid, $file, $media) = @_;
1376 if (!($file eq 'none' || $file eq 'cdrom' ||
1377 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1379 return undef if $file =~ m
|/|;
1381 if ($media && $media eq 'cdrom') {
1382 $file = "local:iso/$file";
1384 $file = "local:$vmid/$file";
1391 sub verify_media_type
{
1392 my ($opt, $vtype, $media) = @_;
1397 if ($media eq 'disk') {
1399 } elsif ($media eq 'cdrom') {
1402 die "internal error";
1405 return if ($vtype eq $etype);
1407 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1410 sub cleanup_drive_path
{
1411 my ($opt, $storecfg, $drive) = @_;
1413 # try to convert filesystem paths to volume IDs
1415 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1416 ($drive->{file
} !~ m
|^/dev/.+|) &&
1417 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1418 ($drive->{file
} !~ m/^\d+$/)) {
1419 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1420 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1421 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1422 verify_media_type
($opt, $vtype, $drive->{media
});
1423 $drive->{file
} = $volid;
1426 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1429 sub parse_hotplug_features
{
1434 return $res if $data eq '0';
1436 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1438 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1439 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1442 die "invalid hotplug feature '$feature'\n";
1448 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1449 sub pve_verify_hotplug_features
{
1450 my ($value, $noerr) = @_;
1452 return $value if parse_hotplug_features
($value);
1454 return undef if $noerr;
1456 die "unable to parse hotplug option\n";
1459 # ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
1460 # [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
1461 # [,rerror=ignore|report|stop][,werror=enospc|ignore|report|stop]
1462 # [,aio=native|threads][,discard=ignore|on][,detect_zeroes=on|off]
1463 # [,iothread=on][,serial=serial][,model=model]
1466 my ($key, $data) = @_;
1468 my ($interface, $index);
1470 if ($key =~ m/^([^\d]+)(\d+)$/) {
1477 my $desc = $key =~ /^unused\d+$/ ?
$alldrive_fmt
1478 : $confdesc->{$key}->{format
};
1480 warn "invalid drive key: $key\n";
1483 my $res = eval { PVE
::JSONSchema
::parse_property_string
($desc, $data) };
1484 return undef if !$res;
1485 $res->{interface
} = $interface;
1486 $res->{index} = $index;
1489 foreach my $opt (qw(bps bps_rd bps_wr)) {
1490 if (my $bps = defined(delete $res->{$opt})) {
1491 if (defined($res->{"m$opt"})) {
1492 warn "both $opt and m$opt specified\n";
1496 $res->{"m$opt"} = sprintf("%.3f", $bps / (1024*1024.0));
1500 # can't use the schema's 'requires' because of the mbps* => bps* "transforming aliases"
1501 for my $requirement (
1502 [mbps_max
=> 'mbps'],
1503 [mbps_rd_max
=> 'mbps_rd'],
1504 [mbps_wr_max
=> 'mbps_wr'],
1505 [miops_max
=> 'miops'],
1506 [miops_rd_max
=> 'miops_rd'],
1507 [miops_wr_max
=> 'miops_wr'],
1508 [bps_max_length
=> 'mbps_max'],
1509 [bps_rd_max_length
=> 'mbps_rd_max'],
1510 [bps_wr_max_length
=> 'mbps_wr_max'],
1511 [iops_max_length
=> 'iops_max'],
1512 [iops_rd_max_length
=> 'iops_rd_max'],
1513 [iops_wr_max_length
=> 'iops_wr_max']) {
1514 my ($option, $requires) = @$requirement;
1515 if ($res->{$option} && !$res->{$requires}) {
1516 warn "$option requires $requires\n";
1521 return undef if $error;
1523 return undef if $res->{mbps_rd
} && $res->{mbps
};
1524 return undef if $res->{mbps_wr
} && $res->{mbps
};
1525 return undef if $res->{iops_rd
} && $res->{iops
};
1526 return undef if $res->{iops_wr
} && $res->{iops
};
1528 if ($res->{media
} && ($res->{media
} eq 'cdrom')) {
1529 return undef if $res->{snapshot
} || $res->{trans
} || $res->{format
};
1530 return undef if $res->{heads
} || $res->{secs
} || $res->{cyls
};
1531 return undef if $res->{interface
} eq 'virtio';
1534 if (my $size = $res->{size
}) {
1535 return undef if !defined($res->{size
} = PVE
::JSONSchema
::parse_size
($size));
1542 my ($vmid, $drive) = @_;
1543 my $data = { %$drive };
1544 delete $data->{$_} for qw(index interface);
1545 return PVE
::JSONSchema
::print_property_string
($data, $alldrive_fmt);
1549 my($fh, $noerr) = @_;
1552 my $SG_GET_VERSION_NUM = 0x2282;
1554 my $versionbuf = "\x00" x
8;
1555 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1557 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1560 my $version = unpack("I", $versionbuf);
1561 if ($version < 30000) {
1562 die "scsi generic interface too old\n" if !$noerr;
1566 my $buf = "\x00" x
36;
1567 my $sensebuf = "\x00" x
8;
1568 my $cmd = pack("C x3 C x1", 0x12, 36);
1570 # see /usr/include/scsi/sg.h
1571 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";
1573 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1574 length($sensebuf), 0, length($buf), $buf,
1575 $cmd, $sensebuf, 6000);
1577 $ret = ioctl($fh, $SG_IO, $packet);
1579 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1583 my @res = unpack($sg_io_hdr_t, $packet);
1584 if ($res[17] || $res[18]) {
1585 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1590 (my $byte0, my $byte1, $res->{vendor
},
1591 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1593 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1594 $res->{type
} = $byte0 & 31;
1602 my $fh = IO
::File-
>new("+<$path") || return undef;
1603 my $res = scsi_inquiry
($fh, 1);
1609 sub machine_type_is_q35
{
1612 return $conf->{machine
} && ($conf->{machine
} =~ m/q35/) ?
1 : 0;
1615 sub print_tabletdevice_full
{
1618 my $q35 = machine_type_is_q35
($conf);
1620 # we use uhci for old VMs because tablet driver was buggy in older qemu
1621 my $usbbus = $q35 ?
"ehci" : "uhci";
1623 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1626 sub print_drivedevice_full
{
1627 my ($storecfg, $conf, $vmid, $drive, $bridges) = @_;
1632 if ($drive->{interface
} eq 'virtio') {
1633 my $pciaddr = print_pci_addr
("$drive->{interface}$drive->{index}", $bridges);
1634 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1635 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread
};
1636 } elsif ($drive->{interface
} eq 'scsi') {
1638 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1639 my $unit = $drive->{index} % $maxdev;
1640 my $devicetype = 'hd';
1642 if (drive_is_cdrom
($drive)) {
1645 if ($drive->{file
} =~ m
|^/|) {
1646 $path = $drive->{file
};
1647 if (my $info = path_is_scsi
($path)) {
1648 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1649 $devicetype = 'block';
1650 } elsif ($info->{type
} == 1) { # tape
1651 $devicetype = 'generic';
1655 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1658 if($path =~ m/^iscsi\:\/\
//){
1659 $devicetype = 'generic';
1663 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1664 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1666 $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}";
1669 } elsif ($drive->{interface
} eq 'ide'){
1671 my $controller = int($drive->{index} / $maxdev);
1672 my $unit = $drive->{index} % $maxdev;
1673 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1675 $device = "ide-$devicetype,bus=ide.$controller,unit=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1676 if ($devicetype eq 'hd' && (my $model = $drive->{model
})) {
1677 $model = URI
::Escape
::uri_unescape
($model);
1678 $device .= ",model=$model";
1680 } elsif ($drive->{interface
} eq 'sata'){
1681 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
1682 my $unit = $drive->{index} % $MAX_SATA_DISKS;
1683 $device = "ide-drive,bus=ahci$controller.$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1684 } elsif ($drive->{interface
} eq 'usb') {
1686 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1688 die "unsupported interface type";
1691 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1696 sub get_initiator_name
{
1699 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return undef;
1700 while (defined(my $line = <$fh>)) {
1701 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1710 sub print_drive_full
{
1711 my ($storecfg, $vmid, $drive) = @_;
1714 my $volid = $drive->{file
};
1717 if (drive_is_cdrom
($drive)) {
1718 $path = get_iso_path
($storecfg, $vmid, $volid);
1720 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1722 $path = PVE
::Storage
::path
($storecfg, $volid);
1723 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1724 $format = qemu_img_format
($scfg, $volname);
1732 my @qemu_drive_options = qw(heads secs cyls trans media format cache rerror werror aio discard);
1733 foreach my $o (@qemu_drive_options) {
1734 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1737 # snapshot only accepts on|off
1738 if (defined($drive->{snapshot
})) {
1739 my $v = $drive->{snapshot
} ?
'on' : 'off';
1740 $opts .= ",snapshot=$v";
1743 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1744 my ($dir, $qmpname) = @$type;
1745 if (my $v = $drive->{"mbps$dir"}) {
1746 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1748 if (my $v = $drive->{"mbps${dir}_max"}) {
1749 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1751 if (my $v = $drive->{"bps${dir}_max_length"}) {
1752 $opts .= ",throttling.bps$qmpname-max-length=$v";
1754 if (my $v = $drive->{"iops${dir}"}) {
1755 $opts .= ",throttling.iops$qmpname=$v";
1757 if (my $v = $drive->{"iops${dir}_max"}) {
1758 $opts .= ",throttling.iops$qmpname-max=$v";
1760 if (my $v = $drive->{"iops${dir}_max_length"}) {
1761 $opts .= ",throttling.iops$qmpname-max-length=$v";
1765 if (my $serial = $drive->{serial
}) {
1766 $serial = URI
::Escape
::uri_unescape
($serial);
1767 $opts .= ",serial=$serial";
1770 $opts .= ",format=$format" if $format && !$drive->{format
};
1772 my $cache_direct = 0;
1774 if (my $cache = $drive->{cache
}) {
1775 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1776 } elsif (!drive_is_cdrom
($drive)) {
1777 $opts .= ",cache=none";
1781 # aio native works only with O_DIRECT
1782 if (!$drive->{aio
}) {
1784 $opts .= ",aio=native";
1786 $opts .= ",aio=threads";
1790 if (!drive_is_cdrom
($drive)) {
1792 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1793 $detectzeroes = 'off';
1794 } elsif ($drive->{discard
}) {
1795 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1797 # This used to be our default with discard not being specified:
1798 $detectzeroes = 'on';
1800 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1803 my $pathinfo = $path ?
"file=$path," : '';
1805 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1808 sub print_netdevice_full
{
1809 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files) = @_;
1811 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
1813 my $device = $net->{model
};
1814 if ($net->{model
} eq 'virtio') {
1815 $device = 'virtio-net-pci';
1818 my $pciaddr = print_pci_addr
("$netid", $bridges);
1819 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1820 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1821 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1822 my $vectors = $net->{queues
} * 2 + 2;
1823 $tmpstr .= ",vectors=$vectors,mq=on";
1825 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1827 if ($use_old_bios_files) {
1829 if ($device eq 'virtio-net-pci') {
1830 $romfile = 'pxe-virtio.rom';
1831 } elsif ($device eq 'e1000') {
1832 $romfile = 'pxe-e1000.rom';
1833 } elsif ($device eq 'ne2k') {
1834 $romfile = 'pxe-ne2k_pci.rom';
1835 } elsif ($device eq 'pcnet') {
1836 $romfile = 'pxe-pcnet.rom';
1837 } elsif ($device eq 'rtl8139') {
1838 $romfile = 'pxe-rtl8139.rom';
1840 $tmpstr .= ",romfile=$romfile" if $romfile;
1846 sub print_netdev_full
{
1847 my ($vmid, $conf, $net, $netid, $hotplug) = @_;
1850 if ($netid =~ m/^net(\d+)$/) {
1854 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1856 my $ifname = "tap${vmid}i$i";
1858 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1859 die "interface name '$ifname' is too long (max 15 character)\n"
1860 if length($ifname) >= 16;
1862 my $vhostparam = '';
1863 $vhostparam = ',vhost=on' if $kernel_has_vhost_net && $net->{model
} eq 'virtio';
1865 my $vmname = $conf->{name
} || "vm$vmid";
1868 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1870 if ($net->{bridge
}) {
1871 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1873 $netdev = "type=user,id=$netid,hostname=$vmname";
1876 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1882 sub print_cpu_device
{
1883 my ($conf, $id) = @_;
1885 my $kvm = $conf->{kvm
} // 1;
1886 my $cpu = $kvm ?
"kvm64" : "qemu64";
1887 if (my $cputype = $conf->{cpu
}) {
1888 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
1889 or die "Cannot parse cpu description: $cputype\n";
1890 $cpu = $cpuconf->{cputype
};
1893 my $cores = $conf->{cores
} || 1;
1895 my $current_core = ($id - 1) % $cores;
1896 my $current_socket = int(($id - 1 - $current_core)/$cores);
1898 return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
1901 sub drive_is_cloudinit
{
1903 return $drive->{file
} =~ m
@[:/]vm-\d
+-cloudinit
(?
:\
.$QEMU_FORMAT_RE)?
$@;
1906 sub drive_is_cdrom
{
1907 my ($drive, $exclude_cloudinit) = @_;
1909 return 0 if $exclude_cloudinit && drive_is_cloudinit
($drive);
1911 return $drive && $drive->{media
} && ($drive->{media
} eq 'cdrom');
1915 sub parse_number_sets
{
1918 foreach my $part (split(/;/, $set)) {
1919 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
1920 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
1921 push @$res, [ $1, $2 ];
1923 die "invalid range: $part\n";
1932 my $res = PVE
::JSONSchema
::parse_property_string
($numa_fmt, $data);
1933 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
1934 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
1941 return undef if !$value;
1943 my $res = PVE
::JSONSchema
::parse_property_string
($hostpci_fmt, $value);
1945 my @idlist = split(/;/, $res->{host
});
1946 delete $res->{host
};
1947 foreach my $id (@idlist) {
1948 if ($id =~ /^$PCIRE$/) {
1950 push @{$res->{pciid
}}, { id
=> $1, function
=> $2 };
1952 my $pcidevices = lspci
($1);
1953 $res->{pciid
} = $pcidevices->{$1};
1956 # should have been caught by parse_property_string already
1957 die "failed to parse PCI id: $id\n";
1963 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1967 my $res = eval { PVE
::JSONSchema
::parse_property_string
($net_fmt, $data) };
1972 if (!defined($res->{macaddr
})) {
1973 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
1974 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
1976 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
() if !defined($res->{macaddr
});
1980 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
1981 sub parse_ipconfig
{
1984 my $res = eval { PVE
::JSONSchema
::parse_property_string
($ipconfig_fmt, $data) };
1990 if ($res->{gw
} && !$res->{ip
}) {
1991 warn 'gateway specified without specifying an IP address';
1994 if ($res->{gw6
} && !$res->{ip6
}) {
1995 warn 'IPv6 gateway specified without specifying an IPv6 address';
1998 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
1999 warn 'gateway specified together with DHCP';
2002 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
2004 warn "IPv6 gateway specified together with $res->{ip6} address";
2008 if (!$res->{ip
} && !$res->{ip6
}) {
2009 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
2018 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
2021 sub add_random_macs
{
2022 my ($settings) = @_;
2024 foreach my $opt (keys %$settings) {
2025 next if $opt !~ m/^net(\d+)$/;
2026 my $net = parse_net
($settings->{$opt});
2028 $settings->{$opt} = print_net
($net);
2032 sub vm_is_volid_owner
{
2033 my ($storecfg, $vmid, $volid) = @_;
2035 if ($volid !~ m
|^/|) {
2037 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
2038 if ($owner && ($owner == $vmid)) {
2046 sub split_flagged_list
{
2047 my $text = shift || '';
2048 $text =~ s/[,;]/ /g;
2050 return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
2053 sub join_flagged_list
{
2054 my ($how, $lst) = @_;
2055 join $how, map { $lst->{$_} . $_ } keys %$lst;
2058 sub vmconfig_delete_pending_option
{
2059 my ($conf, $key, $force) = @_;
2061 delete $conf->{pending
}->{$key};
2062 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2063 $pending_delete_hash->{$key} = $force ?
'!' : '';
2064 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2067 sub vmconfig_undelete_pending_option
{
2068 my ($conf, $key) = @_;
2070 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2071 delete $pending_delete_hash->{$key};
2073 if (%$pending_delete_hash) {
2074 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2076 delete $conf->{pending
}->{delete};
2080 sub vmconfig_register_unused_drive
{
2081 my ($storecfg, $vmid, $conf, $drive) = @_;
2083 if (drive_is_cloudinit
($drive)) {
2084 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
2086 } elsif (!drive_is_cdrom
($drive)) {
2087 my $volid = $drive->{file
};
2088 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
2089 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
2094 sub vmconfig_cleanup_pending
{
2097 # remove pending changes when nothing changed
2099 foreach my $opt (keys %{$conf->{pending
}}) {
2100 if (defined($conf->{$opt}) && ($conf->{pending
}->{$opt} eq $conf->{$opt})) {
2102 delete $conf->{pending
}->{$opt};
2106 my $current_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2107 my $pending_delete_hash = {};
2108 while (my ($opt, $force) = each %$current_delete_hash) {
2109 if (defined($conf->{$opt})) {
2110 $pending_delete_hash->{$opt} = $force;
2116 if (%$pending_delete_hash) {
2117 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2119 delete $conf->{pending
}->{delete};
2125 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
2129 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2130 format_description
=> 'UUID',
2131 description
=> "Set SMBIOS1 UUID.",
2137 format_description
=> 'string',
2138 description
=> "Set SMBIOS1 version.",
2144 format_description
=> 'string',
2145 description
=> "Set SMBIOS1 serial number.",
2151 format_description
=> 'string',
2152 description
=> "Set SMBIOS1 manufacturer.",
2158 format_description
=> 'string',
2159 description
=> "Set SMBIOS1 product ID.",
2165 format_description
=> 'string',
2166 description
=> "Set SMBIOS1 SKU string.",
2172 format_description
=> 'string',
2173 description
=> "Set SMBIOS1 family string.",
2181 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_fmt, $data) };
2188 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
2191 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
2193 PVE
::JSONSchema
::register_format
('pve-qm-bootdisk', \
&verify_bootdisk
);
2194 sub verify_bootdisk
{
2195 my ($value, $noerr) = @_;
2197 return $value if is_valid_drivename
($value);
2199 return undef if $noerr;
2201 die "invalid boot disk '$value'\n";
2204 sub parse_watchdog
{
2207 return undef if !$value;
2209 my $res = eval { PVE
::JSONSchema
::parse_property_string
($watchdog_fmt, $value) };
2214 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
2215 sub verify_usb_device
{
2216 my ($value, $noerr) = @_;
2218 return $value if parse_usb_device
($value);
2220 return undef if $noerr;
2222 die "unable to parse usb device\n";
2225 # add JSON properties for create and set function
2226 sub json_config_properties
{
2229 foreach my $opt (keys %$confdesc) {
2230 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate';
2231 $prop->{$opt} = $confdesc->{$opt};
2237 # return copy of $confdesc_cloudinit to generate documentation
2238 sub cloudinit_config_properties
{
2240 return dclone
($confdesc_cloudinit);
2244 my ($key, $value) = @_;
2246 die "unknown setting '$key'\n" if !$confdesc->{$key};
2248 my $type = $confdesc->{$key}->{type
};
2250 if (!defined($value)) {
2251 die "got undefined value\n";
2254 if ($value =~ m/[\n\r]/) {
2255 die "property contains a line feed\n";
2258 if ($type eq 'boolean') {
2259 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2260 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2261 die "type check ('boolean') failed - got '$value'\n";
2262 } elsif ($type eq 'integer') {
2263 return int($1) if $value =~ m/^(\d+)$/;
2264 die "type check ('integer') failed - got '$value'\n";
2265 } elsif ($type eq 'number') {
2266 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2267 die "type check ('number') failed - got '$value'\n";
2268 } elsif ($type eq 'string') {
2269 if (my $fmt = $confdesc->{$key}->{format
}) {
2270 PVE
::JSONSchema
::check_format
($fmt, $value);
2273 $value =~ s/^\"(.*)\"$/$1/;
2276 die "internal error"
2280 sub check_iommu_support
{
2281 #fixme : need to check IOMMU support
2282 #http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM
2292 my $conf = PVE
::QemuConfig-
>config_file($vmid);
2293 utime undef, undef, $conf;
2297 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
2299 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
2301 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2303 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2305 if ($conf->{template
}) {
2306 # check if any base image is still used by a linked clone
2307 foreach_drive
($conf, sub {
2308 my ($ds, $drive) = @_;
2310 return if drive_is_cdrom
($drive);
2312 my $volid = $drive->{file
};
2314 return if !$volid || $volid =~ m
|^/|;
2316 die "base volume '$volid' is still in use by linked cloned\n"
2317 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2322 # only remove disks owned by this VM
2323 foreach_drive
($conf, sub {
2324 my ($ds, $drive) = @_;
2326 return if drive_is_cdrom
($drive, 1);
2328 my $volid = $drive->{file
};
2330 return if !$volid || $volid =~ m
|^/|;
2332 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2333 return if !$path || !$owner || ($owner != $vmid);
2336 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2338 warn "Could not remove disk '$volid', check manually: $@" if $@;
2342 if ($keep_empty_config) {
2343 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
2348 # also remove unused disk
2350 my $dl = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
2353 PVE
::Storage
::foreach_volid
($dl, sub {
2354 my ($volid, $sid, $volname, $d) = @_;
2355 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2364 sub parse_vm_config
{
2365 my ($filename, $raw) = @_;
2367 return undef if !defined($raw);
2370 digest
=> Digest
::SHA
::sha1_hex
($raw),
2375 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2376 || die "got strange filename '$filename'";
2384 my @lines = split(/\n/, $raw);
2385 foreach my $line (@lines) {
2386 next if $line =~ m/^\s*$/;
2388 if ($line =~ m/^\[PENDING\]\s*$/i) {
2389 $section = 'pending';
2390 if (defined($descr)) {
2392 $conf->{description
} = $descr;
2395 $conf = $res->{$section} = {};
2398 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2400 if (defined($descr)) {
2402 $conf->{description
} = $descr;
2405 $conf = $res->{snapshots
}->{$section} = {};
2409 if ($line =~ m/^\#(.*)\s*$/) {
2410 $descr = '' if !defined($descr);
2411 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2415 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2416 $descr = '' if !defined($descr);
2417 $descr .= PVE
::Tools
::decode_text
($2);
2418 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2419 $conf->{snapstate
} = $1;
2420 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2423 $conf->{$key} = $value;
2424 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2426 if ($section eq 'pending') {
2427 $conf->{delete} = $value; # we parse this later
2429 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2431 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2434 eval { $value = check_type
($key, $value); };
2436 warn "vm $vmid - unable to parse value of '$key' - $@";
2438 $key = 'ide2' if $key eq 'cdrom';
2439 my $fmt = $confdesc->{$key}->{format
};
2440 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2441 my $v = parse_drive
($key, $value);
2442 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2443 $v->{file
} = $volid;
2444 $value = print_drive
($vmid, $v);
2446 warn "vm $vmid - unable to parse value of '$key'\n";
2451 $conf->{$key} = $value;
2456 if (defined($descr)) {
2458 $conf->{description
} = $descr;
2460 delete $res->{snapstate
}; # just to be sure
2465 sub write_vm_config
{
2466 my ($filename, $conf) = @_;
2468 delete $conf->{snapstate
}; # just to be sure
2470 if ($conf->{cdrom
}) {
2471 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2472 $conf->{ide2
} = $conf->{cdrom
};
2473 delete $conf->{cdrom
};
2476 # we do not use 'smp' any longer
2477 if ($conf->{sockets
}) {
2478 delete $conf->{smp
};
2479 } elsif ($conf->{smp
}) {
2480 $conf->{sockets
} = $conf->{smp
};
2481 delete $conf->{cores
};
2482 delete $conf->{smp
};
2485 my $used_volids = {};
2487 my $cleanup_config = sub {
2488 my ($cref, $pending, $snapname) = @_;
2490 foreach my $key (keys %$cref) {
2491 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2492 $key eq 'snapstate' || $key eq 'pending';
2493 my $value = $cref->{$key};
2494 if ($key eq 'delete') {
2495 die "propertry 'delete' is only allowed in [PENDING]\n"
2497 # fixme: check syntax?
2500 eval { $value = check_type
($key, $value); };
2501 die "unable to parse value of '$key' - $@" if $@;
2503 $cref->{$key} = $value;
2505 if (!$snapname && is_valid_drivename
($key)) {
2506 my $drive = parse_drive
($key, $value);
2507 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2512 &$cleanup_config($conf);
2514 &$cleanup_config($conf->{pending
}, 1);
2516 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2517 die "internal error" if $snapname eq 'pending';
2518 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2521 # remove 'unusedX' settings if we re-add a volume
2522 foreach my $key (keys %$conf) {
2523 my $value = $conf->{$key};
2524 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2525 delete $conf->{$key};
2529 my $generate_raw_config = sub {
2530 my ($conf, $pending) = @_;
2534 # add description as comment to top of file
2535 if (defined(my $descr = $conf->{description
})) {
2537 foreach my $cl (split(/\n/, $descr)) {
2538 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2541 $raw .= "#\n" if $pending;
2545 foreach my $key (sort keys %$conf) {
2546 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2547 $raw .= "$key: $conf->{$key}\n";
2552 my $raw = &$generate_raw_config($conf);
2554 if (scalar(keys %{$conf->{pending
}})){
2555 $raw .= "\n[PENDING]\n";
2556 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2559 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2560 $raw .= "\n[$snapname]\n";
2561 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2571 # we use static defaults from our JSON schema configuration
2572 foreach my $key (keys %$confdesc) {
2573 if (defined(my $default = $confdesc->{$key}->{default})) {
2574 $res->{$key} = $default;
2578 my $conf = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
2579 $res->{keyboard
} = $conf->{keyboard
} if $conf->{keyboard
};
2585 my $vmlist = PVE
::Cluster
::get_vmlist
();
2587 return $res if !$vmlist || !$vmlist->{ids
};
2588 my $ids = $vmlist->{ids
};
2590 foreach my $vmid (keys %$ids) {
2591 my $d = $ids->{$vmid};
2592 next if !$d->{node
} || $d->{node
} ne $nodename;
2593 next if !$d->{type
} || $d->{type
} ne 'qemu';
2594 $res->{$vmid}->{exists} = 1;
2599 # test if VM uses local resources (to prevent migration)
2600 sub check_local_resources
{
2601 my ($conf, $noerr) = @_;
2605 $loc_res = 1 if $conf->{hostusb
}; # old syntax
2606 $loc_res = 1 if $conf->{hostpci
}; # old syntax
2608 foreach my $k (keys %$conf) {
2609 next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2610 # sockets are safe: they will recreated be on the target side post-migrate
2611 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2612 $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2615 die "VM uses local resources\n" if $loc_res && !$noerr;
2620 # check if used storages are available on all nodes (use by migrate)
2621 sub check_storage_availability
{
2622 my ($storecfg, $conf, $node) = @_;
2624 foreach_drive
($conf, sub {
2625 my ($ds, $drive) = @_;
2627 my $volid = $drive->{file
};
2630 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2633 # check if storage is available on both nodes
2634 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2635 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2639 # list nodes where all VM images are available (used by has_feature API)
2641 my ($conf, $storecfg) = @_;
2643 my $nodelist = PVE
::Cluster
::get_nodelist
();
2644 my $nodehash = { map { $_ => 1 } @$nodelist };
2645 my $nodename = PVE
::INotify
::nodename
();
2647 foreach_drive
($conf, sub {
2648 my ($ds, $drive) = @_;
2650 my $volid = $drive->{file
};
2653 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2655 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2656 if ($scfg->{disable
}) {
2658 } elsif (my $avail = $scfg->{nodes
}) {
2659 foreach my $node (keys %$nodehash) {
2660 delete $nodehash->{$node} if !$avail->{$node};
2662 } elsif (!$scfg->{shared
}) {
2663 foreach my $node (keys %$nodehash) {
2664 delete $nodehash->{$node} if $node ne $nodename
2674 my ($pidfile, $pid) = @_;
2676 my $fh = IO
::File-
>new("/proc/$pid/cmdline", "r");
2680 return undef if !$line;
2681 my @param = split(/\0/, $line);
2683 my $cmd = $param[0];
2684 return if !$cmd || ($cmd !~ m
|kvm
$| && $cmd !~ m
|qemu-system-x86_64
$|);
2686 for (my $i = 0; $i < scalar (@param); $i++) {
2689 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2690 my $p = $param[$i+1];
2691 return 1 if $p && ($p eq $pidfile);
2700 my ($vmid, $nocheck, $node) = @_;
2702 my $filename = PVE
::QemuConfig-
>config_file($vmid, $node);
2704 die "unable to find configuration file for VM $vmid - no such machine\n"
2705 if !$nocheck && ! -f
$filename;
2707 my $pidfile = pidfile_name
($vmid);
2709 if (my $fd = IO
::File-
>new("<$pidfile")) {
2714 my $mtime = $st->mtime;
2715 if ($mtime > time()) {
2716 warn "file '$filename' modified in future\n";
2719 if ($line =~ m/^(\d+)$/) {
2721 if (check_cmdline
($pidfile, $pid)) {
2722 if (my $pinfo = PVE
::ProcFSTools
::check_process_running
($pid)) {
2734 my $vzlist = config_list
();
2736 my $fd = IO
::Dir-
>new($var_run_tmpdir) || return $vzlist;
2738 while (defined(my $de = $fd->read)) {
2739 next if $de !~ m/^(\d+)\.pid$/;
2741 next if !defined($vzlist->{$vmid});
2742 if (my $pid = check_running
($vmid)) {
2743 $vzlist->{$vmid}->{pid
} = $pid;
2751 my ($storecfg, $conf) = @_;
2753 my $bootdisk = $conf->{bootdisk
};
2754 return undef if !$bootdisk;
2755 return undef if !is_valid_drivename
($bootdisk);
2757 return undef if !$conf->{$bootdisk};
2759 my $drive = parse_drive
($bootdisk, $conf->{$bootdisk});
2760 return undef if !defined($drive);
2762 return undef if drive_is_cdrom
($drive);
2764 my $volid = $drive->{file
};
2765 return undef if !$volid;
2767 return $drive->{size
};
2770 my $last_proc_pid_stat;
2772 # get VM status information
2773 # This must be fast and should not block ($full == false)
2774 # We only query KVM using QMP if $full == true (this can be slow)
2776 my ($opt_vmid, $full) = @_;
2780 my $storecfg = PVE
::Storage
::config
();
2782 my $list = vzlist
();
2783 my $defaults = load_defaults
();
2785 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2787 my $cpucount = $cpuinfo->{cpus
} || 1;
2789 foreach my $vmid (keys %$list) {
2790 next if $opt_vmid && ($vmid ne $opt_vmid);
2792 my $cfspath = PVE
::QemuConfig-
>cfs_config_path($vmid);
2793 my $conf = PVE
::Cluster
::cfs_read_file
($cfspath) || {};
2796 $d->{pid
} = $list->{$vmid}->{pid
};
2798 # fixme: better status?
2799 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
2801 my $size = disksize
($storecfg, $conf);
2802 if (defined($size)) {
2803 $d->{disk
} = 0; # no info available
2804 $d->{maxdisk
} = $size;
2810 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
2811 * ($conf->{cores
} || $defaults->{cores
});
2812 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
2813 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
2815 $d->{name
} = $conf->{name
} || "VM $vmid";
2816 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
2817 : $defaults->{memory
}*(1024*1024);
2819 if ($conf->{balloon
}) {
2820 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
2821 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
2822 : $defaults->{shares
};
2833 $d->{diskwrite
} = 0;
2835 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
2837 $d->{serial
} = 1 if conf_has_serial
($conf);
2842 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
2843 foreach my $dev (keys %$netdev) {
2844 next if $dev !~ m/^tap([1-9]\d*)i/;
2846 my $d = $res->{$vmid};
2849 $d->{netout
} += $netdev->{$dev}->{receive
};
2850 $d->{netin
} += $netdev->{$dev}->{transmit
};
2853 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
2854 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
2859 my $ctime = gettimeofday
;
2861 foreach my $vmid (keys %$list) {
2863 my $d = $res->{$vmid};
2864 my $pid = $d->{pid
};
2867 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
2868 next if !$pstat; # not running
2870 my $used = $pstat->{utime} + $pstat->{stime
};
2872 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
2874 if ($pstat->{vsize
}) {
2875 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
2878 my $old = $last_proc_pid_stat->{$pid};
2880 $last_proc_pid_stat->{$pid} = {
2888 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
2890 if ($dtime > 1000) {
2891 my $dutime = $used - $old->{used
};
2893 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
2894 $last_proc_pid_stat->{$pid} = {
2900 $d->{cpu
} = $old->{cpu
};
2904 return $res if !$full;
2906 my $qmpclient = PVE
::QMPClient-
>new();
2908 my $ballooncb = sub {
2909 my ($vmid, $resp) = @_;
2911 my $info = $resp->{'return'};
2912 return if !$info->{max_mem
};
2914 my $d = $res->{$vmid};
2916 # use memory assigned to VM
2917 $d->{maxmem
} = $info->{max_mem
};
2918 $d->{balloon
} = $info->{actual
};
2920 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
2921 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
2922 $d->{freemem
} = $info->{free_mem
};
2925 $d->{ballooninfo
} = $info;
2928 my $blockstatscb = sub {
2929 my ($vmid, $resp) = @_;
2930 my $data = $resp->{'return'} || [];
2931 my $totalrdbytes = 0;
2932 my $totalwrbytes = 0;
2934 for my $blockstat (@$data) {
2935 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
2936 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
2938 $blockstat->{device
} =~ s/drive-//;
2939 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
2941 $res->{$vmid}->{diskread
} = $totalrdbytes;
2942 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
2945 my $statuscb = sub {
2946 my ($vmid, $resp) = @_;
2948 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
2949 # this fails if ballon driver is not loaded, so this must be
2950 # the last commnand (following command are aborted if this fails).
2951 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
2953 my $status = 'unknown';
2954 if (!defined($status = $resp->{'return'}->{status
})) {
2955 warn "unable to get VM status\n";
2959 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
2962 foreach my $vmid (keys %$list) {
2963 next if $opt_vmid && ($vmid ne $opt_vmid);
2964 next if !$res->{$vmid}->{pid
}; # not running
2965 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
2968 $qmpclient->queue_execute(undef, 2);
2970 foreach my $vmid (keys %$list) {
2971 next if $opt_vmid && ($vmid ne $opt_vmid);
2972 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
2979 my ($conf, $func, @param) = @_;
2981 foreach my $ds (valid_drive_names
()) {
2982 next if !defined($conf->{$ds});
2984 my $drive = parse_drive
($ds, $conf->{$ds});
2987 &$func($ds, $drive, @param);
2992 my ($conf, $func, @param) = @_;
2996 my $test_volid = sub {
2997 my ($volid, $is_cdrom, $replicate, $shared, $snapname) = @_;
3001 $volhash->{$volid}->{cdrom
} //= 1;
3002 $volhash->{$volid}->{cdrom
} = 0 if !$is_cdrom;
3004 $volhash->{$volid}->{replicate
} //= 0;
3005 $volhash->{$volid}->{replicate
} = 1 if $replicate;
3007 $volhash->{$volid}->{shared
} //= 0;
3008 $volhash->{$volid}->{shared
} = 1 if $shared;
3010 $volhash->{$volid}->{referenced_in_config
} //= 0;
3011 $volhash->{$volid}->{referenced_in_config
} = 1 if !defined($snapname);
3013 $volhash->{$volid}->{referenced_in_snapshot
}->{$snapname} = 1
3014 if defined($snapname);
3017 foreach_drive
($conf, sub {
3018 my ($ds, $drive) = @_;
3019 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, undef);
3022 foreach my $snapname (keys %{$conf->{snapshots
}}) {
3023 my $snap = $conf->{snapshots
}->{$snapname};
3024 $test_volid->($snap->{vmstate
}, 0, 1, $snapname);
3025 foreach_drive
($snap, sub {
3026 my ($ds, $drive) = @_;
3027 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, $snapname);
3031 foreach my $volid (keys %$volhash) {
3032 &$func($volid, $volhash->{$volid}, @param);
3036 sub conf_has_serial
{
3039 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3040 if ($conf->{"serial$i"}) {
3048 sub vga_conf_has_spice
{
3051 return 0 if !$vga || $vga !~ m/^qxl([234])?$/;
3056 sub config_to_command
{
3057 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
3060 my $globalFlags = [];
3061 my $machineFlags = [];
3067 my $kvmver = kvm_user_version
();
3068 my $vernum = 0; # unknown
3069 my $ostype = $conf->{ostype
};
3070 my $winversion = windows_version
($ostype);
3071 my $kvm = $conf->{kvm
} // 1;
3073 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n" if (!$cpuinfo->{hvm
} && $kvm);
3075 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
3076 $vernum = $1*1000000+$2*1000;
3077 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
3078 $vernum = $1*1000000+$2*1000+$3;
3081 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
3083 my $have_ovz = -f
'/proc/vz/vestat';
3085 my $q35 = machine_type_is_q35
($conf);
3086 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3087 my $machine_type = $forcemachine || $conf->{machine
};
3088 my $use_old_bios_files = undef;
3089 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3091 my $cpuunits = defined($conf->{cpuunits
}) ?
3092 $conf->{cpuunits
} : $defaults->{cpuunits
};
3094 push @$cmd, '/usr/bin/kvm';
3096 push @$cmd, '-id', $vmid;
3100 my $qmpsocket = qmp_socket
($vmid);
3101 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3102 push @$cmd, '-mon', "chardev=qmp,mode=control";
3105 push @$cmd, '-pidfile' , pidfile_name
($vmid);
3107 push @$cmd, '-daemonize';
3109 if ($conf->{smbios1
}) {
3110 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3113 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3114 die "uefi base image not found\n" if ! -f
$OVMF_CODE;
3118 if (my $efidisk = $conf->{efidisk0
}) {
3119 my $d = PVE
::JSONSchema
::parse_property_string
($efidisk_fmt, $efidisk);
3120 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3121 $format = $d->{format
};
3123 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3124 if (!defined($format)) {
3125 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3126 $format = qemu_img_format
($scfg, $volname);
3130 die "efidisk format must be specified\n"
3131 if !defined($format);
3134 warn "no efidisk configured! Using temporary efivars disk.\n";
3135 $path = "/tmp/$vmid-ovmf.fd";
3136 PVE
::Tools
::file_copy
($OVMF_VARS, $path, -s
$OVMF_VARS);
3140 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$OVMF_CODE";
3141 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
3145 # add usb controllers
3146 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $q35, $usbdesc->{format
}, $MAX_USB_DEVICES);
3147 push @$devices, @usbcontrollers if @usbcontrollers;
3148 my $vga = $conf->{vga
};
3150 my $qxlnum = vga_conf_has_spice
($vga);
3151 $vga = 'qxl' if $qxlnum;
3154 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 9)) {
3155 $vga = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3157 $vga = ($winversion >= 6) ?
'std' : 'cirrus';
3161 # enable absolute mouse coordinates (needed by vnc)
3163 if (defined($conf->{tablet
})) {
3164 $tablet = $conf->{tablet
};
3166 $tablet = $defaults->{tablet
};
3167 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3168 $tablet = 0 if $vga =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3171 push @$devices, '-device', print_tabletdevice_full
($conf) if $tablet;
3174 my $gpu_passthrough;
3177 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3178 my $d = parse_hostpci
($conf->{"hostpci$i"});
3181 my $pcie = $d->{pcie
};
3183 die "q35 machine model is not enabled" if !$q35;
3184 $pciaddr = print_pcie_addr
("hostpci$i");
3186 $pciaddr = print_pci_addr
("hostpci$i", $bridges);
3189 my $rombar = defined($d->{rombar
}) && !$d->{rombar
} ?
',rombar=0' : '';
3190 my $romfile = $d->{romfile
};
3193 if ($d->{'x-vga'}) {
3194 $xvga = ',x-vga=on';
3197 $gpu_passthrough = 1;
3199 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3203 my $pcidevices = $d->{pciid
};
3204 my $multifunction = 1 if @$pcidevices > 1;
3207 foreach my $pcidevice (@$pcidevices) {
3209 my $id = "hostpci$i";
3210 $id .= ".$j" if $multifunction;
3211 my $addr = $pciaddr;
3212 $addr .= ".$j" if $multifunction;
3213 my $devicestr = "vfio-pci,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
3216 $devicestr .= "$rombar$xvga";
3217 $devicestr .= ",multifunction=on" if $multifunction;
3218 $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
3221 push @$devices, '-device', $devicestr;
3227 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES);
3228 push @$devices, @usbdevices if @usbdevices;
3230 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3231 if (my $path = $conf->{"serial$i"}) {
3232 if ($path eq 'socket') {
3233 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3234 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3235 push @$devices, '-device', "isa-serial,chardev=serial$i";
3237 die "no such serial device\n" if ! -c
$path;
3238 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3239 push @$devices, '-device', "isa-serial,chardev=serial$i";
3245 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3246 if (my $path = $conf->{"parallel$i"}) {
3247 die "no such parallel device\n" if ! -c
$path;
3248 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3249 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3250 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3254 my $vmname = $conf->{name
} || "vm$vmid";
3256 push @$cmd, '-name', $vmname;
3259 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3260 $sockets = $conf->{sockets
} if $conf->{sockets
};
3262 my $cores = $conf->{cores
} || 1;
3264 my $maxcpus = $sockets * $cores;
3266 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3268 my $allowed_vcpus = $cpuinfo->{cpus
};
3270 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3271 if ($allowed_vcpus < $maxcpus);
3273 if($hotplug_features->{cpu
} && qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 7)) {
3275 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3276 for (my $i = 2; $i <= $vcpus; $i++) {
3277 my $cpustr = print_cpu_device
($conf,$i);
3278 push @$cmd, '-device', $cpustr;
3283 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3285 push @$cmd, '-nodefaults';
3287 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3289 my $bootindex_hash = {};
3291 foreach my $o (split(//, $bootorder)) {
3292 $bootindex_hash->{$o} = $i*100;
3296 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3298 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3300 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3302 push @$cmd, '-vga', $vga if $vga && $vga !~ m/^serial\d+$/; # for kvm 77 and later
3304 if ($vga && $vga !~ m/^serial\d+$/ && $vga ne 'none'){
3305 my $socket = vnc_socket
($vmid);
3306 push @$cmd, '-vnc', "unix:$socket,x509,password";
3308 push @$cmd, '-nographic';
3312 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3314 my $useLocaltime = $conf->{localtime};
3316 if ($winversion >= 5) { # windows
3317 $useLocaltime = 1 if !defined($conf->{localtime});
3319 # use time drift fix when acpi is enabled
3320 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3321 $tdf = 1 if !defined($conf->{tdf
});
3325 if ($winversion >= 6) {
3326 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3327 push @$cmd, '-no-hpet';
3330 push @$rtcFlags, 'driftfix=slew' if $tdf;
3333 push @$machineFlags, 'accel=tcg';
3336 if ($machine_type) {
3337 push @$machineFlags, "type=${machine_type}";
3340 if ($conf->{startdate
}) {
3341 push @$rtcFlags, "base=$conf->{startdate}";
3342 } elsif ($useLocaltime) {
3343 push @$rtcFlags, 'base=localtime';
3346 my $cpu = $kvm ?
"kvm64" : "qemu64";
3347 if (my $cputype = $conf->{cpu
}) {
3348 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
3349 or die "Cannot parse cpu description: $cputype\n";
3350 $cpu = $cpuconf->{cputype
};
3351 $kvm_off = 1 if $cpuconf->{hidden
};
3353 if (defined(my $flags = $cpuconf->{flags
})) {
3354 push @$cpuFlags, split(";", $flags);
3358 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64';
3360 push @$cpuFlags , '-x2apic'
3361 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3363 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3365 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3367 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3369 push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
3370 push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
3373 add_hyperv_enlightenments
($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios
}, $gpu_passthrough) if $kvm;
3375 push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm;
3377 push @$cpuFlags, 'kvm=off' if $kvm_off;
3379 my $cpu_vendor = $cpu_vendor_list->{$cpu} ||
3380 die "internal error"; # should not happen
3382 push @$cpuFlags, "vendor=${cpu_vendor}"
3383 if $cpu_vendor ne 'default';
3385 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3387 push @$cmd, '-cpu', $cpu;
3389 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3391 push @$cmd, '-S' if $conf->{freeze
};
3393 # set keyboard layout
3394 my $kb = $conf->{keyboard
} || $defaults->{keyboard
};
3395 push @$cmd, '-k', $kb if $kb;
3398 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3399 #push @$cmd, '-soundhw', 'es1370';
3400 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3402 if($conf->{agent
}) {
3403 my $qgasocket = qmp_socket
($vmid, 1);
3404 my $pciaddr = print_pci_addr
("qga0", $bridges);
3405 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3406 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3407 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3415 for(my $i = 1; $i < $qxlnum; $i++){
3416 my $pciaddr = print_pci_addr
("vga$i", $bridges);
3417 push @$cmd, '-device', "qxl,id=vga$i,ram_size=67108864,vram_size=33554432$pciaddr";
3420 # assume other OS works like Linux
3421 push @$cmd, '-global', 'qxl-vga.ram_size=134217728';
3422 push @$cmd, '-global', 'qxl-vga.vram_size=67108864';
3426 my $pciaddr = print_pci_addr
("spice", $bridges);
3428 my $nodename = PVE
::INotify
::nodename
();
3429 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3430 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3431 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3432 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3433 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3435 push @$devices, '-spice', "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3437 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3438 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3439 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3442 # enable balloon by default, unless explicitly disabled
3443 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3444 $pciaddr = print_pci_addr
("balloon0", $bridges);
3445 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3448 if ($conf->{watchdog
}) {
3449 my $wdopts = parse_watchdog
($conf->{watchdog
});
3450 $pciaddr = print_pci_addr
("watchdog", $bridges);
3451 my $watchdog = $wdopts->{model
} || 'i6300esb';
3452 push @$devices, '-device', "$watchdog$pciaddr";
3453 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3457 my $scsicontroller = {};
3458 my $ahcicontroller = {};
3459 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3461 # Add iscsi initiator name if available
3462 if (my $initiator = get_initiator_name
()) {
3463 push @$devices, '-iscsi', "initiator-name=$initiator";
3466 foreach_drive
($conf, sub {
3467 my ($ds, $drive) = @_;
3469 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3470 push @$vollist, $drive->{file
};
3473 # ignore efidisk here, already added in bios/fw handling code above
3474 return if $drive->{interface
} eq 'efidisk';
3476 $use_virtio = 1 if $ds =~ m/^virtio/;
3478 if (drive_is_cdrom
($drive)) {
3479 if ($bootindex_hash->{d
}) {
3480 $drive->{bootindex
} = $bootindex_hash->{d
};
3481 $bootindex_hash->{d
} += 1;
3484 if ($bootindex_hash->{c
}) {
3485 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3486 $bootindex_hash->{c
} += 1;
3490 if($drive->{interface
} eq 'virtio'){
3491 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3494 if ($drive->{interface
} eq 'scsi') {
3496 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3498 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges);
3499 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3502 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3503 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3504 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3505 } elsif ($drive->{iothread
}) {
3506 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3510 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3511 $queues = ",num_queues=$drive->{queues}";
3514 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3515 $scsicontroller->{$controller}=1;
3518 if ($drive->{interface
} eq 'sata') {
3519 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3520 $pciaddr = print_pci_addr
("ahci$controller", $bridges);
3521 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3522 $ahcicontroller->{$controller}=1;
3525 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3526 push @$devices, '-drive',$drive_cmd;
3527 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges);
3530 for (my $i = 0; $i < $MAX_NETS; $i++) {
3531 next if !$conf->{"net$i"};
3532 my $d = parse_net
($conf->{"net$i"});
3535 $use_virtio = 1 if $d->{model
} eq 'virtio';
3537 if ($bootindex_hash->{n
}) {
3538 $d->{bootindex
} = $bootindex_hash->{n
};
3539 $bootindex_hash->{n
} += 1;
3542 my $netdevfull = print_netdev_full
($vmid,$conf,$d,"net$i");
3543 push @$devices, '-netdev', $netdevfull;
3545 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files);
3546 push @$devices, '-device', $netdevicefull;
3551 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3556 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3558 while (my ($k, $v) = each %$bridges) {
3559 $pciaddr = print_pci_addr
("pci.$k");
3560 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3565 if ($conf->{args
}) {
3566 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3570 push @$cmd, @$devices;
3571 push @$cmd, '-rtc', join(',', @$rtcFlags)
3572 if scalar(@$rtcFlags);
3573 push @$cmd, '-machine', join(',', @$machineFlags)
3574 if scalar(@$machineFlags);
3575 push @$cmd, '-global', join(',', @$globalFlags)
3576 if scalar(@$globalFlags);
3578 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3583 return "${var_run_tmpdir}/$vmid.vnc";
3589 my $res = vm_mon_cmd
($vmid, 'query-spice');
3591 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3595 my ($vmid, $qga) = @_;
3596 my $sockettype = $qga ?
'qga' : 'qmp';
3597 return "${var_run_tmpdir}/$vmid.$sockettype";
3602 return "${var_run_tmpdir}/$vmid.pid";
3605 sub vm_devices_list
{
3608 my $res = vm_mon_cmd
($vmid, 'query-pci');
3610 foreach my $pcibus (@$res) {
3611 foreach my $device (@{$pcibus->{devices
}}) {
3612 next if !$device->{'qdev_id'};
3613 if ($device->{'pci_bridge'}) {
3614 $devices->{$device->{'qdev_id'}} = 1;
3615 foreach my $bridge_device (@{$device->{'pci_bridge'}->{devices
}}) {
3616 next if !$bridge_device->{'qdev_id'};
3617 $devices->{$bridge_device->{'qdev_id'}} = 1;
3618 $devices->{$device->{'qdev_id'}}++;
3621 $devices->{$device->{'qdev_id'}} = 1;
3626 my $resblock = vm_mon_cmd
($vmid, 'query-block');
3627 foreach my $block (@$resblock) {
3628 if($block->{device
} =~ m/^drive-(\S+)/){
3633 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
3634 foreach my $mice (@$resmice) {
3635 if ($mice->{name
} eq 'QEMU HID Tablet') {
3636 $devices->{tablet
} = 1;
3641 # for usb devices there is no query-usb
3642 # but we can iterate over the entries in
3643 # qom-list path=/machine/peripheral
3644 my $resperipheral = vm_mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3645 foreach my $per (@$resperipheral) {
3646 if ($per->{name
} =~ m/^usb\d+$/) {
3647 $devices->{$per->{name
}} = 1;
3655 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
3657 my $q35 = machine_type_is_q35
($conf);
3659 my $devices_list = vm_devices_list
($vmid);
3660 return 1 if defined($devices_list->{$deviceid});
3662 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid); # add PCI bridge if we need it for the device
3664 if ($deviceid eq 'tablet') {
3666 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf));
3668 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3670 die "usb hotplug currently not reliable\n";
3671 # since we can't reliably hot unplug all added usb devices
3672 # and usb passthrough disables live migration
3673 # we disable usb hotplugging for now
3674 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
3676 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3678 qemu_iothread_add
($vmid, $deviceid, $device);
3680 qemu_driveadd
($storecfg, $vmid, $device);
3681 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3683 qemu_deviceadd
($vmid, $devicefull);
3684 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3686 eval { qemu_drivedel
($vmid, $deviceid); };
3691 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3694 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
3695 my $pciaddr = print_pci_addr
($deviceid);
3696 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
3698 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
3700 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
3701 qemu_iothread_add
($vmid, $deviceid, $device);
3702 $devicefull .= ",iothread=iothread-$deviceid";
3705 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
3706 $devicefull .= ",num_queues=$device->{queues}";
3709 qemu_deviceadd
($vmid, $devicefull);
3710 qemu_deviceaddverify
($vmid, $deviceid);
3712 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3714 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device);
3715 qemu_driveadd
($storecfg, $vmid, $device);
3717 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3718 eval { qemu_deviceadd
($vmid, $devicefull); };
3720 eval { qemu_drivedel
($vmid, $deviceid); };
3725 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3727 return undef if !qemu_netdevadd
($vmid, $conf, $device, $deviceid);
3729 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
3730 my $use_old_bios_files = undef;
3731 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3733 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files);
3734 qemu_deviceadd
($vmid, $netdevicefull);
3735 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3737 eval { qemu_netdevdel
($vmid, $deviceid); };
3742 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
3745 my $pciaddr = print_pci_addr
($deviceid);
3746 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
3748 qemu_deviceadd
($vmid, $devicefull);
3749 qemu_deviceaddverify
($vmid, $deviceid);
3752 die "can't hotplug device '$deviceid'\n";
3758 # fixme: this should raise exceptions on error!
3759 sub vm_deviceunplug
{
3760 my ($vmid, $conf, $deviceid) = @_;
3762 my $devices_list = vm_devices_list
($vmid);
3763 return 1 if !defined($devices_list->{$deviceid});
3765 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
3767 if ($deviceid eq 'tablet') {
3769 qemu_devicedel
($vmid, $deviceid);
3771 } elsif ($deviceid =~ m/^usb\d+$/) {
3773 die "usb hotplug currently not reliable\n";
3774 # when unplugging usb devices this way,
3775 # there may be remaining usb controllers/hubs
3776 # so we disable it for now
3777 qemu_devicedel
($vmid, $deviceid);
3778 qemu_devicedelverify
($vmid, $deviceid);
3780 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3782 qemu_devicedel
($vmid, $deviceid);
3783 qemu_devicedelverify
($vmid, $deviceid);
3784 qemu_drivedel
($vmid, $deviceid);
3785 qemu_iothread_del
($conf, $vmid, $deviceid);
3787 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3789 qemu_devicedel
($vmid, $deviceid);
3790 qemu_devicedelverify
($vmid, $deviceid);
3791 qemu_iothread_del
($conf, $vmid, $deviceid);
3793 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3795 qemu_devicedel
($vmid, $deviceid);
3796 qemu_drivedel
($vmid, $deviceid);
3797 qemu_deletescsihw
($conf, $vmid, $deviceid);
3799 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3801 qemu_devicedel
($vmid, $deviceid);
3802 qemu_devicedelverify
($vmid, $deviceid);
3803 qemu_netdevdel
($vmid, $deviceid);
3806 die "can't unplug device '$deviceid'\n";
3812 sub qemu_deviceadd
{
3813 my ($vmid, $devicefull) = @_;
3815 $devicefull = "driver=".$devicefull;
3816 my %options = split(/[=,]/, $devicefull);
3818 vm_mon_cmd
($vmid, "device_add" , %options);
3821 sub qemu_devicedel
{
3822 my ($vmid, $deviceid) = @_;
3824 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
3827 sub qemu_iothread_add
{
3828 my($vmid, $deviceid, $device) = @_;
3830 if ($device->{iothread
}) {
3831 my $iothreads = vm_iothreads_list
($vmid);
3832 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
3836 sub qemu_iothread_del
{
3837 my($conf, $vmid, $deviceid) = @_;
3839 my $device = parse_drive
($deviceid, $conf->{$deviceid});
3840 if ($device->{iothread
}) {
3841 my $iothreads = vm_iothreads_list
($vmid);
3842 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
3846 sub qemu_objectadd
{
3847 my($vmid, $objectid, $qomtype) = @_;
3849 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
3854 sub qemu_objectdel
{
3855 my($vmid, $objectid) = @_;
3857 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
3863 my ($storecfg, $vmid, $device) = @_;
3865 my $drive = print_drive_full
($storecfg, $vmid, $device);
3866 $drive =~ s/\\/\\\\/g;
3867 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
3869 # If the command succeeds qemu prints: "OK
"
3870 return 1 if $ret =~ m/OK/s;
3872 die "adding drive failed
: $ret\n";
3876 my($vmid, $deviceid) = @_;
3878 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
3881 return 1 if $ret eq "";
3883 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
3884 return 1 if $ret =~ m/Device \'.*?\' not found/s;
3886 die "deleting drive
$deviceid failed
: $ret\n";
3889 sub qemu_deviceaddverify {
3890 my ($vmid, $deviceid) = @_;
3892 for (my $i = 0; $i <= 5; $i++) {
3893 my $devices_list = vm_devices_list($vmid);
3894 return 1 if defined($devices_list->{$deviceid});
3898 die "error on hotplug device
'$deviceid'\n";
3902 sub qemu_devicedelverify {
3903 my ($vmid, $deviceid) = @_;
3905 # need to verify that the device is correctly removed as device_del
3906 # is async and empty return is not reliable
3908 for (my $i = 0; $i <= 5; $i++) {
3909 my $devices_list = vm_devices_list($vmid);
3910 return 1 if !defined($devices_list->{$deviceid});
3914 die "error on hot-unplugging device
'$deviceid'\n";
3917 sub qemu_findorcreatescsihw {
3918 my ($storecfg, $conf, $vmid, $device) = @_;
3920 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3922 my $scsihwid="$controller_prefix$controller";
3923 my $devices_list = vm_devices_list($vmid);
3925 if(!defined($devices_list->{$scsihwid})) {
3926 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device);
3932 sub qemu_deletescsihw {
3933 my ($conf, $vmid, $opt) = @_;
3935 my $device = parse_drive($opt, $conf->{$opt});
3937 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
3938 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
3942 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3944 my $devices_list = vm_devices_list($vmid);
3945 foreach my $opt (keys %{$devices_list}) {
3946 if (PVE::QemuServer::is_valid_drivename($opt)) {
3947 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
3948 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
3954 my $scsihwid="scsihw
$controller";
3956 vm_deviceunplug($vmid, $conf, $scsihwid);
3961 sub qemu_add_pci_bridge {
3962 my ($storecfg, $conf, $vmid, $device) = @_;
3968 print_pci_addr($device, $bridges);
3970 while (my ($k, $v) = each %$bridges) {
3973 return 1 if !defined($bridgeid) || $bridgeid < 1;
3975 my $bridge = "pci
.$bridgeid";
3976 my $devices_list = vm_devices_list($vmid);
3978 if (!defined($devices_list->{$bridge})) {
3979 vm_deviceplug($storecfg, $conf, $vmid, $bridge);
3985 sub qemu_set_link_status {
3986 my ($vmid, $device, $up) = @_;
3988 vm_mon_cmd($vmid, "set_link
", name => $device,
3989 up => $up ? JSON::true : JSON::false);
3992 sub qemu_netdevadd {
3993 my ($vmid, $conf, $device, $deviceid) = @_;
3995 my $netdev = print_netdev_full($vmid, $conf, $device, $deviceid, 1);
3996 my %options = split(/[=,]/, $netdev);
3998 vm_mon_cmd($vmid, "netdev_add
", %options);
4002 sub qemu_netdevdel {
4003 my ($vmid, $deviceid) = @_;
4005 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
4008 sub qemu_usb_hotplug {
4009 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
4013 # remove the old one first
4014 vm_deviceunplug($vmid, $conf, $deviceid);
4016 # check if xhci controller is necessary and available
4017 if ($device->{usb3}) {
4019 my $devicelist = vm_devices_list($vmid);
4021 if (!$devicelist->{xhci}) {
4022 my $pciaddr = print_pci_addr("xhci
");
4023 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4026 my $d = parse_usb_device($device->{host});
4027 $d->{usb3} = $device->{usb3};
4030 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d);
4033 sub qemu_cpu_hotplug {
4034 my ($vmid, $conf, $vcpus) = @_;
4036 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4039 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4040 $sockets = $conf->{sockets} if $conf->{sockets};
4041 my $cores = $conf->{cores} || 1;
4042 my $maxcpus = $sockets * $cores;
4044 $vcpus = $maxcpus if !$vcpus;
4046 die "you can
't add more vcpus than maxcpus\n"
4047 if $vcpus > $maxcpus;
4049 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4051 if ($vcpus < $currentvcpus) {
4053 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4055 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4056 qemu_devicedel($vmid, "cpu$i");
4058 my $currentrunningvcpus = undef;
4060 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4061 last if scalar(@{$currentrunningvcpus}) == $i-1;
4062 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4066 #update conf after each succesfull cpu unplug
4067 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4068 PVE::QemuConfig->write_config($vmid, $conf);
4071 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4077 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4078 die "vcpus in running vm does not match its configuration\n"
4079 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4081 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4083 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4084 my $cpustr = print_cpu_device($conf, $i);
4085 qemu_deviceadd($vmid, $cpustr);
4088 my $currentrunningvcpus = undef;
4090 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4091 last if scalar(@{$currentrunningvcpus}) == $i;
4092 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4096 #update conf after each succesfull cpu hotplug
4097 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4098 PVE::QemuConfig->write_config($vmid, $conf);
4102 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4103 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4108 sub qemu_block_set_io_throttle {
4109 my ($vmid, $deviceid,
4110 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4111 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4112 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4113 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4115 return if !check_running($vmid) ;
4117 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4119 bps_rd => int($bps_rd),
4120 bps_wr => int($bps_wr),
4122 iops_rd => int($iops_rd),
4123 iops_wr => int($iops_wr),
4124 bps_max => int($bps_max),
4125 bps_rd_max => int($bps_rd_max),
4126 bps_wr_max => int($bps_wr_max),
4127 iops_max => int($iops_max),
4128 iops_rd_max => int($iops_rd_max),
4129 iops_wr_max => int($iops_wr_max),
4130 bps_max_length => int($bps_max_length),
4131 bps_rd_max_length => int($bps_rd_max_length),
4132 bps_wr_max_length => int($bps_wr_max_length),
4133 iops_max_length => int($iops_max_length),
4134 iops_rd_max_length => int($iops_rd_max_length),
4135 iops_wr_max_length => int($iops_wr_max_length),
4140 # old code, only used to shutdown old VM after update
4142 my ($fh, $timeout) = @_;
4144 my $sel = new IO::Select;
4151 while (scalar (@ready = $sel->can_read($timeout))) {
4153 if ($count = $fh->sysread($buf, 8192)) {
4154 if ($buf =~ /^(.*)\(qemu\) $/s) {
4161 if (!defined($count)) {
4168 die "monitor read timeout\n" if !scalar(@ready);
4173 # old code, only used to shutdown old VM after update
4174 sub vm_monitor_command {
4175 my ($vmid, $cmdstr, $nocheck) = @_;
4180 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
4182 my $sname = "${var_run_tmpdir}/$vmid.mon";
4184 my $sock = IO::Socket::UNIX->new( Peer => $sname ) ||
4185 die "unable to connect to VM $vmid socket - $!\n";
4189 # hack: migrate sometime blocks the monitor (when migrate_downtime
4191 if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
4192 $timeout = 60*60; # 1 hour
4196 my $data = __read_avail($sock, $timeout);
4198 if ($data !~ m/^QEMU\s+(\S+)\s+monitor\s/) {
4199 die "got unexpected qemu monitor banner\n";
4202 my $sel = new IO::Select;
4205 if (!scalar(my @ready = $sel->can_write($timeout))) {
4206 die "monitor write error - timeout";
4209 my $fullcmd = "$cmdstr\r";
4211 # syslog('info
', "VM $vmid monitor command: $cmdstr");
4214 if (!($b = $sock->syswrite($fullcmd)) || ($b != length($fullcmd))) {
4215 die "monitor write error - $!";
4218 return if ($cmdstr eq 'q
') || ($cmdstr eq 'quit
');
4222 if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
4223 $timeout = 60*60; # 1 hour
4224 } elsif ($cmdstr =~ m/^(eject|change)/) {
4225 $timeout = 60; # note: cdrom mount command is slow
4227 if ($res = __read_avail($sock, $timeout)) {
4229 my @lines = split("\r?\n", $res);
4231 shift @lines if $lines[0] !~ m/^unknown command/; # skip echo
4233 $res = join("\n", @lines);
4241 syslog("err", "VM $vmid monitor command failed - $err");
4248 sub qemu_block_resize {
4249 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4251 my $running = check_running($vmid);
4253 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4255 return if !$running;
4257 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4261 sub qemu_volume_snapshot {
4262 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4264 my $running = check_running($vmid);
4266 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4267 vm_mon_cmd($vmid, "snapshot-drive", device => $deviceid, name => $snap);
4269 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4273 sub qemu_volume_snapshot_delete {
4274 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4276 my $running = check_running($vmid);
4278 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4279 vm_mon_cmd($vmid, "delete-drive-snapshot", device => $deviceid, name => $snap);
4281 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4285 sub set_migration_caps {
4291 "auto-converge" => 1,
4293 "x-rdma-pin-all" => 0,
4298 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4300 for my $supported_capability (@$supported_capabilities) {
4302 capability => $supported_capability->{capability},
4303 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4307 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4310 my $fast_plug_option = {
4318 'vmstatestorage
' => 1,
4321 # hotplug changes in [PENDING]
4322 # $selection hash can be used to only apply specified options, for
4323 # example: { cores => 1 } (only apply changed 'cores
')
4324 # $errors ref is used to return error messages
4325 sub vmconfig_hotplug_pending {
4326 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4328 my $defaults = load_defaults();
4330 # commit values which do not have any impact on running VM first
4331 # Note: those option cannot raise errors, we we do not care about
4332 # $selection and always apply them.
4334 my $add_error = sub {
4335 my ($opt, $msg) = @_;
4336 $errors->{$opt} = "hotplug problem - $msg";
4340 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4341 if ($fast_plug_option->{$opt}) {
4342 $conf->{$opt} = $conf->{pending}->{$opt};
4343 delete $conf->{pending}->{$opt};
4349 PVE::QemuConfig->write_config($vmid, $conf);
4350 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4353 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4355 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4356 while (my ($opt, $force) = each %$pending_delete_hash) {
4357 next if $selection && !$selection->{$opt};
4359 if ($opt eq 'hotplug
') {
4360 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4361 } elsif ($opt eq 'tablet
') {
4362 die "skip\n" if !$hotplug_features->{usb};
4363 if ($defaults->{tablet}) {
4364 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4366 vm_deviceunplug($vmid, $conf, $opt);
4368 } elsif ($opt =~ m/^usb\d+/) {
4370 # since we cannot reliably hot unplug usb devices
4371 # we are disabling it
4372 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4373 vm_deviceunplug($vmid, $conf, $opt);
4374 } elsif ($opt eq 'vcpus
') {
4375 die "skip\n" if !$hotplug_features->{cpu};
4376 qemu_cpu_hotplug($vmid, $conf, undef);
4377 } elsif ($opt eq 'balloon
') {
4378 # enable balloon device is not hotpluggable
4379 die "skip\n" if !defined($conf->{balloon}) || $conf->{balloon};
4380 } elsif ($fast_plug_option->{$opt}) {
4382 } elsif ($opt =~ m/^net(\d+)$/) {
4383 die "skip\n" if !$hotplug_features->{network};
4384 vm_deviceunplug($vmid, $conf, $opt);
4385 } elsif (is_valid_drivename($opt)) {
4386 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4387 vm_deviceunplug($vmid, $conf, $opt);
4388 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4389 } elsif ($opt =~ m/^memory$/) {
4390 die "skip\n" if !$hotplug_features->{memory};
4391 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4392 } elsif ($opt eq 'cpuunits
') {
4393 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4394 } elsif ($opt eq 'cpulimit
') {
4395 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4401 &$add_error($opt, $err) if $err ne "skip\n";
4403 # save new config if hotplug was successful
4404 delete $conf->{$opt};
4405 vmconfig_undelete_pending_option($conf, $opt);
4406 PVE::QemuConfig->write_config($vmid, $conf);
4407 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4411 my $apply_pending_cloudinit;
4412 $apply_pending_cloudinit = sub {
4413 my ($key, $value) = @_;
4414 $apply_pending_cloudinit = sub {}; # once is enough
4416 my @cloudinit_opts = keys %$confdesc_cloudinit;
4417 foreach my $opt (keys %{$conf->{pending}}) {
4418 next if !grep { $_ eq $opt } @cloudinit_opts;
4419 $conf->{$opt} = delete $conf->{pending}->{$opt};
4422 my $new_conf = { %$conf };
4423 $new_conf->{$key} = $value;
4424 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4427 foreach my $opt (keys %{$conf->{pending}}) {
4428 next if $selection && !$selection->{$opt};
4429 my $value = $conf->{pending}->{$opt};
4431 if ($opt eq 'hotplug
') {
4432 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4433 } elsif ($opt eq 'tablet
') {
4434 die "skip\n" if !$hotplug_features->{usb};
4436 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4437 } elsif ($value == 0) {
4438 vm_deviceunplug($vmid, $conf, $opt);
4440 } elsif ($opt =~ m/^usb\d+$/) {
4442 # since we cannot reliably hot unplug usb devices
4443 # we are disabling it
4444 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4445 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4446 die "skip\n" if !$d;
4447 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d);
4448 } elsif ($opt eq 'vcpus
') {
4449 die "skip\n" if !$hotplug_features->{cpu};
4450 qemu_cpu_hotplug($vmid, $conf, $value);
4451 } elsif ($opt eq 'balloon
') {
4452 # enable/disable balloning device is not hotpluggable
4453 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4454 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4455 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4457 # allow manual ballooning if shares is set to zero
4458 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4459 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4460 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4462 } elsif ($opt =~ m/^net(\d+)$/) {
4463 # some changes can be done without hotplug
4464 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4465 $vmid, $opt, $value);
4466 } elsif (is_valid_drivename($opt)) {
4467 # some changes can be done without hotplug
4468 my $drive = parse_drive($opt, $value);
4469 if (drive_is_cloudinit($drive)) {
4470 &$apply_pending_cloudinit($opt, $value);
4472 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4473 $vmid, $opt, $value, 1);
4474 } elsif ($opt =~ m/^memory$/) { #dimms
4475 die "skip\n" if !$hotplug_features->{memory};
4476 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4477 } elsif ($opt eq 'cpuunits
') {
4478 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4479 } elsif ($opt eq 'cpulimit
') {
4480 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4481 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4483 die "skip\n"; # skip non-hot-pluggable options
4487 &$add_error($opt, $err) if $err ne "skip\n";
4489 # save new config if hotplug was successful
4490 $conf->{$opt} = $value;
4491 delete $conf->{pending}->{$opt};
4492 PVE::QemuConfig->write_config($vmid, $conf);
4493 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4498 sub try_deallocate_drive {
4499 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4501 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4502 my $volid = $drive->{file};
4503 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4504 my $sid = PVE::Storage::parse_volume_id($volid);
4505 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4507 # check if the disk is really unused
4508 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4509 if is_volume_in_use($storecfg, $conf, $key, $volid);
4510 PVE::Storage::vdisk_free($storecfg, $volid);
4513 # If vm is not owner of this disk remove from config
4521 sub vmconfig_delete_or_detach_drive {
4522 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4524 my $drive = parse_drive($opt, $conf->{$opt});
4526 my $rpcenv = PVE::RPCEnvironment::get();
4527 my $authuser = $rpcenv->get_user();
4530 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4531 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4533 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4537 sub vmconfig_apply_pending {
4538 my ($vmid, $conf, $storecfg) = @_;
4542 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4543 while (my ($opt, $force) = each %$pending_delete_hash) {
4544 die "internal error" if $opt =~ m/^unused/;
4545 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4546 if (!defined($conf->{$opt})) {
4547 vmconfig_undelete_pending_option($conf, $opt);
4548 PVE::QemuConfig->write_config($vmid, $conf);
4549 } elsif (is_valid_drivename($opt)) {
4550 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4551 vmconfig_undelete_pending_option($conf, $opt);
4552 delete $conf->{$opt};
4553 PVE::QemuConfig->write_config($vmid, $conf);
4555 vmconfig_undelete_pending_option($conf, $opt);
4556 delete $conf->{$opt};
4557 PVE::QemuConfig->write_config($vmid, $conf);
4561 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4563 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4564 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4566 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4567 # skip if nothing changed
4568 } elsif (is_valid_drivename($opt)) {
4569 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4570 if defined($conf->{$opt});
4571 $conf->{$opt} = $conf->{pending}->{$opt};
4573 $conf->{$opt} = $conf->{pending}->{$opt};
4576 delete $conf->{pending}->{$opt};
4577 PVE::QemuConfig->write_config($vmid, $conf);
4581 my $safe_num_ne = sub {
4584 return 0 if !defined($a) && !defined($b);
4585 return 1 if !defined($a);
4586 return 1 if !defined($b);
4591 my $safe_string_ne = sub {
4594 return 0 if !defined($a) && !defined($b);
4595 return 1 if !defined($a);
4596 return 1 if !defined($b);
4601 sub vmconfig_update_net {
4602 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value) = @_;
4604 my $newnet = parse_net($value);
4606 if ($conf->{$opt}) {
4607 my $oldnet = parse_net($conf->{$opt});
4609 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4610 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4611 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4612 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4614 # for non online change, we try to hot-unplug
4615 die "skip\n" if !$hotplug;
4616 vm_deviceunplug($vmid, $conf, $opt);
4619 die "internal error" if $opt !~ m/net(\d+)/;
4620 my $iface = "tap${vmid}i$1";
4622 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4623 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4624 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4625 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4626 PVE::Network::tap_unplug($iface);
4627 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4628 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4629 # Rate can be applied on its own but any change above needs to
4630 # include the rate in tap_plug since OVS resets everything.
4631 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4634 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4635 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4643 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet);
4649 sub vmconfig_update_disk {
4650 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force) = @_;
4652 # fixme: do we need force?
4654 my $drive = parse_drive($opt, $value);
4656 if ($conf->{$opt}) {
4658 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4660 my $media = $drive->{media} || 'disk
';
4661 my $oldmedia = $old_drive->{media} || 'disk
';
4662 die "unable to change media type\n" if $media ne $oldmedia;
4664 if (!drive_is_cdrom($old_drive)) {
4666 if ($drive->{file} ne $old_drive->{file}) {
4668 die "skip\n" if !$hotplug;
4670 # unplug and register as unused
4671 vm_deviceunplug($vmid, $conf, $opt);
4672 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4675 # update existing disk
4677 # skip non hotpluggable value
4678 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4679 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4680 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4681 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
4686 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4687 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4688 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4689 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4690 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4691 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4692 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4693 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4694 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4695 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4696 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4697 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4698 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4699 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4700 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4701 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4702 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4703 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4705 qemu_block_set_io_throttle($vmid,"drive-$opt",
4706 ($drive->{mbps} || 0)*1024*1024,
4707 ($drive->{mbps_rd} || 0)*1024*1024,
4708 ($drive->{mbps_wr} || 0)*1024*1024,
4709 $drive->{iops} || 0,
4710 $drive->{iops_rd} || 0,
4711 $drive->{iops_wr} || 0,
4712 ($drive->{mbps_max} || 0)*1024*1024,
4713 ($drive->{mbps_rd_max} || 0)*1024*1024,
4714 ($drive->{mbps_wr_max} || 0)*1024*1024,
4715 $drive->{iops_max} || 0,
4716 $drive->{iops_rd_max} || 0,
4717 $drive->{iops_wr_max} || 0,
4718 $drive->{bps_max_length} || 1,
4719 $drive->{bps_rd_max_length} || 1,
4720 $drive->{bps_wr_max_length} || 1,
4721 $drive->{iops_max_length} || 1,
4722 $drive->{iops_rd_max_length} || 1,
4723 $drive->{iops_wr_max_length} || 1);
4732 if ($drive->{file} eq 'none
') {
4733 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
4734 if (drive_is_cloudinit($old_drive)) {
4735 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
4738 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4739 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
4740 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
4748 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4750 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
4751 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive);
4755 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
4756 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
4758 PVE::QemuConfig->lock_config($vmid, sub {
4759 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
4761 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
4763 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4765 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
4767 if (!$statefile && scalar(keys %{$conf->{pending}})) {
4768 vmconfig_apply_pending($vmid, $conf, $storecfg);
4769 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4772 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
4774 my $defaults = load_defaults();
4776 # set environment variable useful inside network script
4777 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
4779 my $local_volumes = {};
4781 if ($targetstorage) {
4782 foreach_drive($conf, sub {
4783 my ($ds, $drive) = @_;
4785 return if drive_is_cdrom($drive);
4787 my $volid = $drive->{file};
4791 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
4793 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4794 return if $scfg->{shared};
4795 $local_volumes->{$ds} = [$volid, $storeid, $volname];
4800 foreach my $opt (sort keys %$local_volumes) {
4802 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
4803 my $drive = parse_drive($opt, $conf->{$opt});
4805 #if remote storage is specified, use default format
4806 if ($targetstorage && $targetstorage ne "1") {
4807 $storeid = $targetstorage;
4808 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
4809 $format = $defFormat;
4811 #else we use same format than original
4812 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4813 $format = qemu_img_format($scfg, $volid);
4816 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
4817 my $newdrive = $drive;
4818 $newdrive->{format} = $format;
4819 $newdrive->{file} = $newvolid;
4820 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
4821 $local_volumes->{$opt} = $drivestr;
4822 #pass drive to conf for command line
4823 $conf->{$opt} = $drivestr;
4827 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
4829 my $migrate_port = 0;
4832 if ($statefile eq 'tcp
') {
4833 my $localip = "localhost";
4834 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
4835 my $nodename = PVE::INotify::nodename();
4837 if (!defined($migration_type)) {
4838 if (defined($datacenterconf->{migration}->{type})) {
4839 $migration_type = $datacenterconf->{migration}->{type};
4841 $migration_type = 'secure
';
4845 if ($migration_type eq 'insecure
') {
4846 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
4847 if ($migrate_network_addr) {
4848 $localip = $migrate_network_addr;
4850 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
4853 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4856 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4857 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4858 $migrate_uri = "tcp:${localip}:${migrate_port}";
4859 push @$cmd, '-incoming
', $migrate_uri;
4862 } elsif ($statefile eq 'unix
') {
4863 # should be default for secure migrations as a ssh TCP forward
4864 # tunnel is not deterministic reliable ready and fails regurarly
4865 # to set up in time, so use UNIX socket forwards
4866 my $socket_addr = "/run/qemu-server/$vmid.migrate";
4867 unlink $socket_addr;
4869 $migrate_uri = "unix:$socket_addr";
4871 push @$cmd, '-incoming
', $migrate_uri;
4875 push @$cmd, '-loadstate
', $statefile;
4882 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
4883 my $d = parse_hostpci($conf->{"hostpci$i"});
4885 my $pcidevices = $d->{pciid};
4886 foreach my $pcidevice (@$pcidevices) {
4887 my $pciid = $pcidevice->{id}.".".$pcidevice->{function};
4889 my $info = pci_device_info("0000:$pciid");
4890 die "IOMMU not present\n" if !check_iommu_support();
4891 die "no pci device info for device '$pciid'\n" if !$info;
4892 die "can't unbind
/bind pci group to vfio
'$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
4893 die "can
't reset pci device '$pciid'\n" if $info->{has_fl_reset} and !pci_dev_reset($info);
4897 PVE::Storage::activate_volumes($storecfg, $vollist);
4899 if (!check_running($vmid, 1) && -d "/sys/fs/cgroup/systemd/qemu.slice/$vmid.scope") {
4901 push @$cmd, '/bin/systemctl
', 'stop
', "$vmid.scope";
4902 eval { run_command($cmd); };
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
};