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
;
38 use Time
::HiRes
qw(gettimeofday);
39 use File
::Copy
qw(copy);
42 my $EDK2_FW_BASE = '/usr/share/pve-edk2-firmware/';
43 my $OVMF_CODE = "$EDK2_FW_BASE/OVMF_CODE.fd";
44 my $OVMF_VARS = "$EDK2_FW_BASE/OVMF_VARS.fd";
46 my $qemu_snap_storage = {rbd
=> 1, sheepdog
=> 1};
48 my $cpuinfo = PVE
::ProcFSTools
::read_cpuinfo
();
50 my $QEMU_FORMAT_RE = qr/raw|cow|qcow|qcow2|qed|vmdk|cloop/;
52 # Note about locking: we use flock on the config file protect
53 # against concurent actions.
54 # Aditionaly, we have a 'lock' setting in the config file. This
55 # can be set to 'migrate', 'backup', 'snapshot' or 'rollback'. Most actions are not
56 # allowed when such lock is set. But you can ignore this kind of
57 # lock with the --skiplock flag.
59 cfs_register_file
('/qemu-server/',
63 PVE
::JSONSchema
::register_standard_option
('pve-qm-stateuri', {
64 description
=> "Some command save/restore state from this location.",
70 PVE
::JSONSchema
::register_standard_option
('pve-snapshot-name', {
71 description
=> "The name of the snapshot.",
72 type
=> 'string', format
=> 'pve-configid',
76 PVE
::JSONSchema
::register_standard_option
('pve-qm-image-format', {
78 enum
=> [qw(raw cow qcow qed qcow2 vmdk cloop)],
79 description
=> "The drive's backing file's data format.",
83 #no warnings 'redefine';
86 my ($controller, $vmid, $option, $value) = @_;
88 my $path = "/sys/fs/cgroup/$controller/qemu.slice/$vmid.scope/$option";
89 PVE
::ProcFSTools
::write_proc_entry
($path, $value);
93 my $nodename = PVE
::INotify
::nodename
();
95 mkdir "/etc/pve/nodes/$nodename";
96 my $confdir = "/etc/pve/nodes/$nodename/qemu-server";
99 my $var_run_tmpdir = "/var/run/qemu-server";
100 mkdir $var_run_tmpdir;
102 my $lock_dir = "/var/lock/qemu-server";
105 my $pcisysfs = "/sys/bus/pci";
107 my $cpu_vendor_list = {
109 486 => 'GenuineIntel',
110 pentium
=> 'GenuineIntel',
111 pentium2
=> 'GenuineIntel',
112 pentium3
=> 'GenuineIntel',
113 coreduo
=> 'GenuineIntel',
114 core2duo
=> 'GenuineIntel',
115 Conroe
=> 'GenuineIntel',
116 Penryn
=> 'GenuineIntel',
117 Nehalem
=> 'GenuineIntel',
118 'Nehalem-IBRS' => 'GenuineIntel',
119 Westmere
=> 'GenuineIntel',
120 'Westmere-IBRS' => 'GenuineIntel',
121 SandyBridge
=> 'GenuineIntel',
122 'SandyBridge-IBRS' => 'GenuineIntel',
123 IvyBridge
=> 'GenuineIntel',
124 'IvyBridge-IBRS' => 'GenuineIntel',
125 Haswell
=> 'GenuineIntel',
126 'Haswell-IBRS' => 'GenuineIntel',
127 'Haswell-noTSX' => 'GenuineIntel',
128 'Haswell-noTSX-IBRS' => 'GenuineIntel',
129 Broadwell
=> 'GenuineIntel',
130 'Broadwell-IBRS' => 'GenuineIntel',
131 'Broadwell-noTSX' => 'GenuineIntel',
132 'Broadwell-noTSX-IBRS' => 'GenuineIntel',
133 'Skylake-Client' => 'GenuineIntel',
134 'Skylake-Client-IBRS' => 'GenuineIntel',
135 'Skylake-Server' => 'GenuineIntel',
136 'Skylake-Server-IBRS' => 'GenuineIntel',
139 athlon
=> 'AuthenticAMD',
140 phenom
=> 'AuthenticAMD',
141 Opteron_G1
=> 'AuthenticAMD',
142 Opteron_G2
=> 'AuthenticAMD',
143 Opteron_G3
=> 'AuthenticAMD',
144 Opteron_G4
=> 'AuthenticAMD',
145 Opteron_G5
=> 'AuthenticAMD',
146 EPYC
=> 'AuthenticAMD',
147 'EPYC-IBPB' => 'AuthenticAMD',
149 # generic types, use vendor from host node
158 my $cpu_flag = qr/[+-](pcid|spec-ctrl|ibpb|ssbd|virt-ssbd|amd-ssbd|amd-no-ssb|pdpe1gb)/;
162 description
=> "Emulated CPU type.",
164 enum
=> [ sort { "\L$a" cmp "\L$b" } keys %$cpu_vendor_list ],
169 description
=> "Do not identify as a KVM virtual machine.",
175 description
=> "List of additional CPU flags separated by ';'."
176 . " Use '+FLAG' to enable, '-FLAG' to disable a flag."
177 . " Currently supported flags: 'pcid', 'spec-ctrl', 'ibpb', 'ssbd', 'virt-ssbd', 'amd-ssbd', 'amd-no-ssb', 'pdpe1gb'.",
178 format_description
=> '+FLAG[;-FLAG...]',
180 pattern
=> qr/$cpu_flag(;$cpu_flag)*/,
189 enum
=> [qw(i6300esb ib700)],
190 description
=> "Watchdog type to emulate.",
191 default => 'i6300esb',
196 enum
=> [qw(reset shutdown poweroff pause debug none)],
197 description
=> "The action to perform if after activation the guest fails to poll the watchdog in time.",
201 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', $watchdog_fmt);
205 description
=> "Enable/disable Qemu GuestAgent.",
210 fstrim_cloned_disks
=> {
211 description
=> "Run fstrim after cloning/moving a disk.",
222 description
=> "Specifies whether a VM will be started during system bootup.",
228 description
=> "Automatic restart after crash (currently ignored).",
233 type
=> 'string', format
=> 'pve-hotplug-features',
234 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'.",
235 default => 'network,disk,usb',
240 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
246 description
=> "Lock/unlock the VM.",
247 enum
=> [qw(migrate backup snapshot rollback)],
252 description
=> "Limit of CPU usage.",
253 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.",
261 description
=> "CPU weight for a VM.",
262 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.",
270 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
277 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
283 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. Auto-ballooning is done by pvestatd.",
291 description
=> "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.cfg' configuration file.".
292 "It should not be necessary to set it.",
293 enum
=> PVE
::Tools
::kvmkeymaplist
(),
298 type
=> 'string', format
=> 'dns-name',
299 description
=> "Set a name for the VM. Only used on the configuration web interface.",
304 description
=> "SCSI controller model",
305 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
311 description
=> "Description for the VM. Only used on the configuration web interface. This is saved as comment inside the configuration file.",
316 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 l24 l26 solaris)],
317 description
=> "Specify guest operating system.",
318 verbose_description
=> <<EODESC,
319 Specify guest operating system. This is used to enable special
320 optimization/features for specific operating systems:
323 other;; unspecified OS
324 wxp;; Microsoft Windows XP
325 w2k;; Microsoft Windows 2000
326 w2k3;; Microsoft Windows 2003
327 w2k8;; Microsoft Windows 2008
328 wvista;; Microsoft Windows Vista
329 win7;; Microsoft Windows 7
330 win8;; Microsoft Windows 8/2012/2012r2
331 win10;; Microsoft Windows 10/2016
332 l24;; Linux 2.4 Kernel
333 l26;; Linux 2.6/3.X Kernel
334 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
340 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
341 pattern
=> '[acdn]{1,4}',
346 type
=> 'string', format
=> 'pve-qm-bootdisk',
347 description
=> "Enable booting from specified disk.",
348 pattern
=> '(ide|sata|scsi|virtio)\d+',
353 description
=> "The number of CPUs. Please use option -sockets instead.",
360 description
=> "The number of CPU sockets.",
367 description
=> "The number of cores per socket.",
374 description
=> "Enable/disable NUMA.",
380 description
=> "Enable/disable hugepages memory.",
381 enum
=> [qw(any 2 1024)],
386 description
=> "Number of hotplugged vcpus.",
393 description
=> "Enable/disable ACPI.",
398 description
=> "Enable/disable Qemu GuestAgent and its properties.",
400 format
=> $agent_fmt,
405 description
=> "Enable/disable KVM hardware virtualization.",
411 description
=> "Enable/disable time drift fix.",
417 description
=> "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
422 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
427 description
=> "Select the VGA type.",
428 verbose_description
=> "Select the VGA type. If you want to use high resolution" .
429 " modes (>= 1280x1024x16) then you should use the options " .
430 "'std' or 'vmware'. Default is 'std' for win8/win7/w2k8, and " .
431 "'cirrus' for other OS types. The 'qxl' option enables the SPICE " .
432 "display sever. For win* OS you can select how many independent " .
433 "displays you want, Linux guests can add displays them self. " .
434 "You can also run without any graphic card, using a serial device" .
436 enum
=> [qw(std cirrus vmware qxl serial0 serial1 serial2 serial3 qxl2 qxl3 qxl4)],
440 type
=> 'string', format
=> 'pve-qm-watchdog',
441 description
=> "Create a virtual hardware watchdog device.",
442 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled" .
443 " (by a guest action), the watchdog must be periodically polled " .
444 "by an agent inside the guest or else the watchdog will reset " .
445 "the guest (or execute the respective action specified)",
450 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
451 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'.",
452 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
455 startup
=> get_standard_option
('pve-startup-order'),
459 description
=> "Enable/disable Template.",
465 description
=> "Arbitrary arguments passed to kvm.",
466 verbose_description
=> <<EODESCR,
467 Arbitrary arguments passed to kvm, for example:
469 args: -no-reboot -no-hpet
471 NOTE: this option is for experts only.
478 description
=> "Enable/disable the USB tablet device.",
479 verbose_description
=> "Enable/disable the USB tablet device. This device is " .
480 "usually needed to allow absolute mouse positioning with VNC. " .
481 "Else the mouse runs out of sync with normal VNC clients. " .
482 "If you're running lots of console-only guests on one host, " .
483 "you may consider disabling this to save some context switches. " .
484 "This is turned off by default if you use spice (-vga=qxl).",
489 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
493 migrate_downtime
=> {
496 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
502 type
=> 'string', format
=> 'pve-qm-ide',
503 typetext
=> '<volume>',
504 description
=> "This is an alias for option -ide2",
508 description
=> "Emulated CPU type.",
512 parent
=> get_standard_option
('pve-snapshot-name', {
514 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
518 description
=> "Timestamp for snapshots.",
524 type
=> 'string', format
=> 'pve-volume-id',
525 description
=> "Reference to a volume which stores the VM state. This is used internally for snapshots.",
527 vmstatestorage
=> get_standard_option
('pve-storage-id', {
528 description
=> "Default storage for VM state volumes/files.",
532 description
=> "Specific the Qemu machine type.",
534 pattern
=> '(pc|pc(-i440fx)?-\d+\.\d+(\.pxe)?|q35|pc-q35-\d+\.\d+(\.pxe)?)',
539 description
=> "Specify SMBIOS type 1 fields.",
540 type
=> 'string', format
=> 'pve-qm-smbios1',
547 description
=> "Sets the protection flag of the VM. This will disable the remove VM and remove disk operations.",
553 enum
=> [ qw(seabios ovmf) ],
554 description
=> "Select BIOS implementation.",
555 default => 'seabios',
559 my $confdesc_cloudinit = {
563 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.',
564 enum
=> ['configdrive2', 'nocloud'],
569 description
=> "cloud-init: User name to change ssh keys and password for instead of the image's configured default user.",
574 description
=> 'cloud-init: Password to assign the user. Using this is generally not recommended. Use ssh keys instead. Also note that older cloud-init versions do not support hashed passwords.',
579 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.",
583 type
=> 'string', format
=> 'address-list',
584 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.",
589 format
=> 'urlencoded',
590 description
=> "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
594 # what about other qemu settings ?
596 #machine => 'string',
609 ##soundhw => 'string',
611 while (my ($k, $v) = each %$confdesc) {
612 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
615 my $MAX_IDE_DISKS = 4;
616 my $MAX_SCSI_DISKS = 14;
617 my $MAX_VIRTIO_DISKS = 16;
618 my $MAX_SATA_DISKS = 6;
619 my $MAX_USB_DEVICES = 5;
621 my $MAX_UNUSED_DISKS = 8;
622 my $MAX_HOSTPCI_DEVICES = 4;
623 my $MAX_SERIAL_PORTS = 4;
624 my $MAX_PARALLEL_PORTS = 3;
630 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
631 description
=> "CPUs accessing this NUMA node.",
632 format_description
=> "id[-id];...",
636 description
=> "Amount of memory this NUMA node provides.",
641 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
642 description
=> "Host NUMA nodes to use.",
643 format_description
=> "id[-id];...",
648 enum
=> [qw(preferred bind interleave)],
649 description
=> "NUMA allocation policy.",
653 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
656 type
=> 'string', format
=> $numa_fmt,
657 description
=> "NUMA topology.",
659 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
661 for (my $i = 0; $i < $MAX_NUMA; $i++) {
662 $confdesc->{"numa$i"} = $numadesc;
665 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
666 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
667 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
668 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
670 my $net_fmt_bridge_descr = <<__EOD__;
671 Bridge to attach the network device to. The Proxmox VE standard bridge
674 If you do not specify a bridge, we create a kvm user (NATed) network
675 device, which provides DHCP and DNS services. The following addresses
682 The DHCP server assign addresses to the guest starting from 10.0.2.15.
688 pattern
=> qr/[0-9a-f]{2}(?::[0-9a-f]{2}){5}/i,
689 description
=> "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
690 format_description
=> "XX:XX:XX:XX:XX:XX",
695 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'.",
696 enum
=> $nic_model_list,
699 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
702 description
=> $net_fmt_bridge_descr,
703 format_description
=> 'bridge',
708 minimum
=> 0, maximum
=> 16,
709 description
=> 'Number of packet queues to be used on the device.',
715 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
720 minimum
=> 1, maximum
=> 4094,
721 description
=> 'VLAN tag to apply to packets on this interface.',
726 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
727 description
=> 'VLAN trunks to pass through this interface.',
728 format_description
=> 'vlanid[;vlanid...]',
733 description
=> 'Whether this interface should be protected by the firewall.',
738 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
745 type
=> 'string', format
=> $net_fmt,
746 description
=> "Specify network devices.",
749 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
754 format
=> 'pve-ipv4-config',
755 format_description
=> 'IPv4Format/CIDR',
756 description
=> 'IPv4 address in CIDR format.',
763 format_description
=> 'GatewayIPv4',
764 description
=> 'Default gateway for IPv4 traffic.',
770 format
=> 'pve-ipv6-config',
771 format_description
=> 'IPv6Format/CIDR',
772 description
=> 'IPv6 address in CIDR format.',
779 format_description
=> 'GatewayIPv6',
780 description
=> 'Default gateway for IPv6 traffic.',
785 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
788 type
=> 'string', format
=> 'pve-qm-ipconfig',
789 description
=> <<'EODESCR',
790 cloud-init: Specify IP addresses and gateways for the corresponding interface.
792 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
794 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided.
795 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration.
797 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4.
800 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
802 for (my $i = 0; $i < $MAX_NETS; $i++) {
803 $confdesc->{"net$i"} = $netdesc;
804 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
807 foreach my $key (keys %$confdesc_cloudinit) {
808 $confdesc->{$key} = $confdesc_cloudinit->{$key};
811 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
812 sub verify_volume_id_or_qm_path
{
813 my ($volid, $noerr) = @_;
815 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
819 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
820 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
822 return undef if $noerr;
830 my %drivedesc_base = (
831 volume
=> { alias
=> 'file' },
834 format
=> 'pve-volume-id-or-qm-path',
836 format_description
=> 'volume',
837 description
=> "The drive's backing volume.",
841 enum
=> [qw(cdrom disk)],
842 description
=> "The drive's media type.",
848 description
=> "Force the drive's physical geometry to have a specific cylinder count.",
853 description
=> "Force the drive's physical geometry to have a specific head count.",
858 description
=> "Force the drive's physical geometry to have a specific sector count.",
863 enum
=> [qw(none lba auto)],
864 description
=> "Force disk geometry bios translation mode.",
869 description
=> "Controls qemu's snapshot mode feature."
870 . " If activated, changes made to the disk are temporary and will"
871 . " be discarded when the VM is shutdown.",
876 enum
=> [qw(none writethrough writeback unsafe directsync)],
877 description
=> "The drive's cache mode",
880 format
=> get_standard_option
('pve-qm-image-format'),
883 format
=> 'disk-size',
884 format_description
=> 'DiskSize',
885 description
=> "Disk size. This is purely informational and has no effect.",
890 description
=> "Whether the drive should be included when making backups.",
895 description
=> 'Whether the drive should considered for replication jobs.',
901 enum
=> [qw(ignore report stop)],
902 description
=> 'Read error action.',
907 enum
=> [qw(enospc ignore report stop)],
908 description
=> 'Write error action.',
913 enum
=> [qw(native threads)],
914 description
=> 'AIO type to use.',
919 enum
=> [qw(ignore on)],
920 description
=> 'Controls whether to pass discard/trim requests to the underlying storage.',
925 description
=> 'Controls whether to detect and try to optimize writes of zeroes.',
930 format
=> 'urlencoded',
931 format_description
=> 'serial',
932 maxLength
=> 20*3, # *3 since it's %xx url enoded
933 description
=> "The drive's reported serial number, url-encoded, up to 20 bytes long.",
938 description
=> 'Mark this locally-managed volume as available on all nodes',
939 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!",
945 my %iothread_fmt = ( iothread
=> {
947 description
=> "Whether to use iothreads for this drive",
954 format
=> 'urlencoded',
955 format_description
=> 'model',
956 maxLength
=> 40*3, # *3 since it's %xx url enoded
957 description
=> "The drive's reported model name, url-encoded, up to 40 bytes long.",
965 description
=> "Number of queues.",
971 my %scsiblock_fmt = (
974 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",
980 my $add_throttle_desc = sub {
981 my ($key, $type, $what, $unit, $longunit, $minimum) = @_;
984 format_description
=> $unit,
985 description
=> "Maximum $what in $longunit.",
988 $d->{minimum
} = $minimum if defined($minimum);
989 $drivedesc_base{$key} = $d;
991 # throughput: (leaky bucket)
992 $add_throttle_desc->('bps', 'integer', 'r/w speed', 'bps', 'bytes per second');
993 $add_throttle_desc->('bps_rd', 'integer', 'read speed', 'bps', 'bytes per second');
994 $add_throttle_desc->('bps_wr', 'integer', 'write speed', 'bps', 'bytes per second');
995 $add_throttle_desc->('mbps', 'number', 'r/w speed', 'mbps', 'megabytes per second');
996 $add_throttle_desc->('mbps_rd', 'number', 'read speed', 'mbps', 'megabytes per second');
997 $add_throttle_desc->('mbps_wr', 'number', 'write speed', 'mbps', 'megabytes per second');
998 $add_throttle_desc->('iops', 'integer', 'r/w I/O', 'iops', 'operations per second');
999 $add_throttle_desc->('iops_rd', 'integer', 'read I/O', 'iops', 'operations per second');
1000 $add_throttle_desc->('iops_wr', 'integer', 'write I/O', 'iops', 'operations per second');
1002 # pools: (pool of IO before throttling starts taking effect)
1003 $add_throttle_desc->('mbps_max', 'number', 'unthrottled r/w pool', 'mbps', 'megabytes per second');
1004 $add_throttle_desc->('mbps_rd_max', 'number', 'unthrottled read pool', 'mbps', 'megabytes per second');
1005 $add_throttle_desc->('mbps_wr_max', 'number', 'unthrottled write pool', 'mbps', 'megabytes per second');
1006 $add_throttle_desc->('iops_max', 'integer', 'unthrottled r/w I/O pool', 'iops', 'operations per second');
1007 $add_throttle_desc->('iops_rd_max', 'integer', 'unthrottled read I/O pool', 'iops', 'operations per second');
1008 $add_throttle_desc->('iops_wr_max', 'integer', 'unthrottled write I/O pool', 'iops', 'operations per second');
1011 $add_throttle_desc->('bps_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
1012 $add_throttle_desc->('bps_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
1013 $add_throttle_desc->('bps_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1014 $add_throttle_desc->('iops_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
1015 $add_throttle_desc->('iops_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
1016 $add_throttle_desc->('iops_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1019 $drivedesc_base{'bps_rd_length'} = { alias
=> 'bps_rd_max_length' };
1020 $drivedesc_base{'bps_wr_length'} = { alias
=> 'bps_wr_max_length' };
1021 $drivedesc_base{'iops_rd_length'} = { alias
=> 'iops_rd_max_length' };
1022 $drivedesc_base{'iops_wr_length'} = { alias
=> 'iops_wr_max_length' };
1028 PVE
::JSONSchema
::register_format
("pve-qm-ide", $ide_fmt);
1032 type
=> 'string', format
=> $ide_fmt,
1033 description
=> "Use volume as IDE hard disk or CD-ROM (n is 0 to " .($MAX_IDE_DISKS -1) . ").",
1035 PVE
::JSONSchema
::register_standard_option
("pve-qm-ide", $idedesc);
1045 type
=> 'string', format
=> $scsi_fmt,
1046 description
=> "Use volume as SCSI hard disk or CD-ROM (n is 0 to " . ($MAX_SCSI_DISKS - 1) . ").",
1048 PVE
::JSONSchema
::register_standard_option
("pve-qm-scsi", $scsidesc);
1055 type
=> 'string', format
=> $sata_fmt,
1056 description
=> "Use volume as SATA hard disk or CD-ROM (n is 0 to " . ($MAX_SATA_DISKS - 1). ").",
1058 PVE
::JSONSchema
::register_standard_option
("pve-qm-sata", $satadesc);
1066 type
=> 'string', format
=> $virtio_fmt,
1067 description
=> "Use volume as VIRTIO hard disk (n is 0 to " . ($MAX_VIRTIO_DISKS - 1) . ").",
1069 PVE
::JSONSchema
::register_standard_option
("pve-qm-virtio", $virtiodesc);
1071 my $alldrive_fmt = {
1080 volume
=> { alias
=> 'file' },
1083 format
=> 'pve-volume-id-or-qm-path',
1085 format_description
=> 'volume',
1086 description
=> "The drive's backing volume.",
1088 format
=> get_standard_option
('pve-qm-image-format'),
1091 format
=> 'disk-size',
1092 format_description
=> 'DiskSize',
1093 description
=> "Disk size. This is purely informational and has no effect.",
1098 my $efidisk_desc = {
1100 type
=> 'string', format
=> $efidisk_fmt,
1101 description
=> "Configure a Disk for storing EFI vars",
1104 PVE
::JSONSchema
::register_standard_option
("pve-qm-efidisk", $efidisk_desc);
1109 type
=> 'string', format
=> 'pve-qm-usb-device',
1110 format_description
=> 'HOSTUSBDEVICE|spice',
1111 description
=> <<EODESCR,
1112 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1114 'bus-port(.port)*' (decimal numbers) or
1115 'vendor_id:product_id' (hexadeciaml numbers) or
1118 You can use the 'lsusb -t' command to list existing usb devices.
1120 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1122 The value 'spice' can be used to add a usb redirection devices for spice.
1128 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).",
1135 type
=> 'string', format
=> $usb_fmt,
1136 description
=> "Configure an USB device (n is 0 to 4).",
1138 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
1140 # NOTE: the match-groups of this regex are used in parse_hostpci
1141 my $PCIRE = qr/([a-f0-9]{2}:[a-f0-9]{2})(?:\.([a-f0-9]))?/;
1146 pattern
=> qr/$PCIRE(;$PCIRE)*/,
1147 format_description
=> 'HOSTPCIID[;HOSTPCIID2...]',
1148 description
=> <<EODESCR,
1149 Host PCI device pass through. The PCI ID of a host's PCI device or a list
1150 of PCI virtual functions of the host. HOSTPCIID syntax is:
1152 'bus:dev.func' (hexadecimal numbers)
1154 You can us the 'lspci' command to list existing PCI devices.
1159 description
=> "Specify whether or not the device's ROM will be visible in the guest's memory map.",
1165 pattern
=> '[^,;]+',
1166 format_description
=> 'string',
1167 description
=> "Custom pci device rom filename (must be located in /usr/share/kvm/).",
1172 description
=> "Choose the PCI-express bus (needs the 'q35' machine model).",
1178 description
=> "Enable vfio-vga device support.",
1183 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', $hostpci_fmt);
1187 type
=> 'string', format
=> 'pve-qm-hostpci',
1188 description
=> "Map host PCI devices into guest.",
1189 verbose_description
=> <<EODESCR,
1190 Map host PCI devices into guest.
1192 NOTE: This option allows direct access to host hardware. So it is no longer
1193 possible to migrate such machines - use with special care.
1195 CAUTION: Experimental! User reported problems with this option.
1198 PVE
::JSONSchema
::register_standard_option
("pve-qm-hostpci", $hostpcidesc);
1203 pattern
=> '(/dev/.+|socket)',
1204 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1205 verbose_description
=> <<EODESCR,
1206 Create a serial device inside the VM (n is 0 to 3), and pass through a
1207 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1208 host side (use 'qm terminal' to open a terminal connection).
1210 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
1212 CAUTION: Experimental! User reported problems with this option.
1219 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1220 description
=> "Map host parallel devices (n is 0 to 2).",
1221 verbose_description
=> <<EODESCR,
1222 Map host parallel devices (n is 0 to 2).
1224 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1226 CAUTION: Experimental! User reported problems with this option.
1230 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1231 $confdesc->{"parallel$i"} = $paralleldesc;
1234 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1235 $confdesc->{"serial$i"} = $serialdesc;
1238 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
1239 $confdesc->{"hostpci$i"} = $hostpcidesc;
1242 for (my $i = 0; $i < $MAX_IDE_DISKS; $i++) {
1243 $drivename_hash->{"ide$i"} = 1;
1244 $confdesc->{"ide$i"} = $idedesc;
1247 for (my $i = 0; $i < $MAX_SATA_DISKS; $i++) {
1248 $drivename_hash->{"sata$i"} = 1;
1249 $confdesc->{"sata$i"} = $satadesc;
1252 for (my $i = 0; $i < $MAX_SCSI_DISKS; $i++) {
1253 $drivename_hash->{"scsi$i"} = 1;
1254 $confdesc->{"scsi$i"} = $scsidesc ;
1257 for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++) {
1258 $drivename_hash->{"virtio$i"} = 1;
1259 $confdesc->{"virtio$i"} = $virtiodesc;
1262 $drivename_hash->{efidisk0
} = 1;
1263 $confdesc->{efidisk0
} = $efidisk_desc;
1265 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1266 $confdesc->{"usb$i"} = $usbdesc;
1271 type
=> 'string', format
=> 'pve-volume-id',
1272 description
=> "Reference to unused volumes. This is used internally, and should not be modified manually.",
1275 for (my $i = 0; $i < $MAX_UNUSED_DISKS; $i++) {
1276 $confdesc->{"unused$i"} = $unuseddesc;
1279 my $kvm_api_version = 0;
1283 return $kvm_api_version if $kvm_api_version;
1285 my $fh = IO
::File-
>new("</dev/kvm") ||
1288 if (my $v = $fh->ioctl(KVM_GET_API_VERSION
(), 0)) {
1289 $kvm_api_version = $v;
1294 return $kvm_api_version;
1297 my $kvm_user_version;
1299 sub kvm_user_version
{
1301 return $kvm_user_version if $kvm_user_version;
1303 $kvm_user_version = 'unknown';
1307 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1308 $kvm_user_version = $2;
1312 eval { run_command
("kvm -version", outfunc
=> $code); };
1315 return $kvm_user_version;
1319 my $kernel_has_vhost_net = -c
'/dev/vhost-net';
1321 sub valid_drive_names
{
1322 # order is important - used to autoselect boot disk
1323 return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
1324 (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
1325 (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))),
1326 (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))),
1330 sub is_valid_drivename
{
1333 return defined($drivename_hash->{$dev});
1338 return defined($confdesc->{$key});
1342 return $nic_model_list;
1345 sub os_list_description
{
1349 wxp
=> 'Windows XP',
1350 w2k
=> 'Windows 2000',
1351 w2k3
=>, 'Windows 2003',
1352 w2k8
=> 'Windows 2008',
1353 wvista
=> 'Windows Vista',
1354 win7
=> 'Windows 7',
1355 win8
=> 'Windows 8/2012',
1356 win10
=> 'Windows 10/2016',
1364 sub get_cdrom_path
{
1366 return $cdrom_path if $cdrom_path;
1368 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1369 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1370 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1374 my ($storecfg, $vmid, $cdrom) = @_;
1376 if ($cdrom eq 'cdrom') {
1377 return get_cdrom_path
();
1378 } elsif ($cdrom eq 'none') {
1380 } elsif ($cdrom =~ m
|^/|) {
1383 return PVE
::Storage
::path
($storecfg, $cdrom);
1387 # try to convert old style file names to volume IDs
1388 sub filename_to_volume_id
{
1389 my ($vmid, $file, $media) = @_;
1391 if (!($file eq 'none' || $file eq 'cdrom' ||
1392 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1394 return undef if $file =~ m
|/|;
1396 if ($media && $media eq 'cdrom') {
1397 $file = "local:iso/$file";
1399 $file = "local:$vmid/$file";
1406 sub verify_media_type
{
1407 my ($opt, $vtype, $media) = @_;
1412 if ($media eq 'disk') {
1414 } elsif ($media eq 'cdrom') {
1417 die "internal error";
1420 return if ($vtype eq $etype);
1422 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1425 sub cleanup_drive_path
{
1426 my ($opt, $storecfg, $drive) = @_;
1428 # try to convert filesystem paths to volume IDs
1430 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1431 ($drive->{file
} !~ m
|^/dev/.+|) &&
1432 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1433 ($drive->{file
} !~ m/^\d+$/)) {
1434 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1435 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1436 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1437 verify_media_type
($opt, $vtype, $drive->{media
});
1438 $drive->{file
} = $volid;
1441 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1444 sub parse_hotplug_features
{
1449 return $res if $data eq '0';
1451 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1453 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1454 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1457 die "invalid hotplug feature '$feature'\n";
1463 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1464 sub pve_verify_hotplug_features
{
1465 my ($value, $noerr) = @_;
1467 return $value if parse_hotplug_features
($value);
1469 return undef if $noerr;
1471 die "unable to parse hotplug option\n";
1474 # ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
1475 # [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
1476 # [,rerror=ignore|report|stop][,werror=enospc|ignore|report|stop]
1477 # [,aio=native|threads][,discard=ignore|on][,detect_zeroes=on|off]
1478 # [,iothread=on][,serial=serial][,model=model]
1481 my ($key, $data) = @_;
1483 my ($interface, $index);
1485 if ($key =~ m/^([^\d]+)(\d+)$/) {
1492 my $desc = $key =~ /^unused\d+$/ ?
$alldrive_fmt
1493 : $confdesc->{$key}->{format
};
1495 warn "invalid drive key: $key\n";
1498 my $res = eval { PVE
::JSONSchema
::parse_property_string
($desc, $data) };
1499 return undef if !$res;
1500 $res->{interface
} = $interface;
1501 $res->{index} = $index;
1504 foreach my $opt (qw(bps bps_rd bps_wr)) {
1505 if (my $bps = defined(delete $res->{$opt})) {
1506 if (defined($res->{"m$opt"})) {
1507 warn "both $opt and m$opt specified\n";
1511 $res->{"m$opt"} = sprintf("%.3f", $bps / (1024*1024.0));
1515 # can't use the schema's 'requires' because of the mbps* => bps* "transforming aliases"
1516 for my $requirement (
1517 [mbps_max
=> 'mbps'],
1518 [mbps_rd_max
=> 'mbps_rd'],
1519 [mbps_wr_max
=> 'mbps_wr'],
1520 [miops_max
=> 'miops'],
1521 [miops_rd_max
=> 'miops_rd'],
1522 [miops_wr_max
=> 'miops_wr'],
1523 [bps_max_length
=> 'mbps_max'],
1524 [bps_rd_max_length
=> 'mbps_rd_max'],
1525 [bps_wr_max_length
=> 'mbps_wr_max'],
1526 [iops_max_length
=> 'iops_max'],
1527 [iops_rd_max_length
=> 'iops_rd_max'],
1528 [iops_wr_max_length
=> 'iops_wr_max']) {
1529 my ($option, $requires) = @$requirement;
1530 if ($res->{$option} && !$res->{$requires}) {
1531 warn "$option requires $requires\n";
1536 return undef if $error;
1538 return undef if $res->{mbps_rd
} && $res->{mbps
};
1539 return undef if $res->{mbps_wr
} && $res->{mbps
};
1540 return undef if $res->{iops_rd
} && $res->{iops
};
1541 return undef if $res->{iops_wr
} && $res->{iops
};
1543 if ($res->{media
} && ($res->{media
} eq 'cdrom')) {
1544 return undef if $res->{snapshot
} || $res->{trans
} || $res->{format
};
1545 return undef if $res->{heads
} || $res->{secs
} || $res->{cyls
};
1546 return undef if $res->{interface
} eq 'virtio';
1549 if (my $size = $res->{size
}) {
1550 return undef if !defined($res->{size
} = PVE
::JSONSchema
::parse_size
($size));
1557 my ($vmid, $drive) = @_;
1558 my $data = { %$drive };
1559 delete $data->{$_} for qw(index interface);
1560 return PVE
::JSONSchema
::print_property_string
($data, $alldrive_fmt);
1564 my($fh, $noerr) = @_;
1567 my $SG_GET_VERSION_NUM = 0x2282;
1569 my $versionbuf = "\x00" x
8;
1570 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1572 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1575 my $version = unpack("I", $versionbuf);
1576 if ($version < 30000) {
1577 die "scsi generic interface too old\n" if !$noerr;
1581 my $buf = "\x00" x
36;
1582 my $sensebuf = "\x00" x
8;
1583 my $cmd = pack("C x3 C x1", 0x12, 36);
1585 # see /usr/include/scsi/sg.h
1586 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";
1588 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1589 length($sensebuf), 0, length($buf), $buf,
1590 $cmd, $sensebuf, 6000);
1592 $ret = ioctl($fh, $SG_IO, $packet);
1594 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1598 my @res = unpack($sg_io_hdr_t, $packet);
1599 if ($res[17] || $res[18]) {
1600 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1605 (my $byte0, my $byte1, $res->{vendor
},
1606 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1608 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1609 $res->{type
} = $byte0 & 31;
1617 my $fh = IO
::File-
>new("+<$path") || return undef;
1618 my $res = scsi_inquiry
($fh, 1);
1624 sub machine_type_is_q35
{
1627 return $conf->{machine
} && ($conf->{machine
} =~ m/q35/) ?
1 : 0;
1630 sub print_tabletdevice_full
{
1633 my $q35 = machine_type_is_q35
($conf);
1635 # we use uhci for old VMs because tablet driver was buggy in older qemu
1636 my $usbbus = $q35 ?
"ehci" : "uhci";
1638 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1641 sub print_drivedevice_full
{
1642 my ($storecfg, $conf, $vmid, $drive, $bridges) = @_;
1647 if ($drive->{interface
} eq 'virtio') {
1648 my $pciaddr = print_pci_addr
("$drive->{interface}$drive->{index}", $bridges);
1649 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1650 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread
};
1651 } elsif ($drive->{interface
} eq 'scsi') {
1653 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1654 my $unit = $drive->{index} % $maxdev;
1655 my $devicetype = 'hd';
1657 if (drive_is_cdrom
($drive)) {
1660 if ($drive->{file
} =~ m
|^/|) {
1661 $path = $drive->{file
};
1662 if (my $info = path_is_scsi
($path)) {
1663 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1664 $devicetype = 'block';
1665 } elsif ($info->{type
} == 1) { # tape
1666 $devicetype = 'generic';
1670 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1673 if($path =~ m/^iscsi\:\/\
//){
1674 $devicetype = 'generic';
1678 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1679 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1681 $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}";
1684 } elsif ($drive->{interface
} eq 'ide'){
1686 my $controller = int($drive->{index} / $maxdev);
1687 my $unit = $drive->{index} % $maxdev;
1688 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1690 $device = "ide-$devicetype,bus=ide.$controller,unit=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1691 if ($devicetype eq 'hd' && (my $model = $drive->{model
})) {
1692 $model = URI
::Escape
::uri_unescape
($model);
1693 $device .= ",model=$model";
1695 } elsif ($drive->{interface
} eq 'sata'){
1696 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
1697 my $unit = $drive->{index} % $MAX_SATA_DISKS;
1698 $device = "ide-drive,bus=ahci$controller.$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1699 } elsif ($drive->{interface
} eq 'usb') {
1701 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1703 die "unsupported interface type";
1706 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1708 if (my $serial = $drive->{serial
}) {
1709 $serial = URI
::Escape
::uri_unescape
($serial);
1710 $device .= ",serial=$serial";
1717 sub get_initiator_name
{
1720 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return undef;
1721 while (defined(my $line = <$fh>)) {
1722 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1731 sub print_drive_full
{
1732 my ($storecfg, $vmid, $drive) = @_;
1735 my $volid = $drive->{file
};
1738 if (drive_is_cdrom
($drive)) {
1739 $path = get_iso_path
($storecfg, $vmid, $volid);
1741 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1743 $path = PVE
::Storage
::path
($storecfg, $volid);
1744 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1745 $format = qemu_img_format
($scfg, $volname);
1753 my @qemu_drive_options = qw(heads secs cyls trans media format cache rerror werror aio discard);
1754 foreach my $o (@qemu_drive_options) {
1755 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1758 # snapshot only accepts on|off
1759 if (defined($drive->{snapshot
})) {
1760 my $v = $drive->{snapshot
} ?
'on' : 'off';
1761 $opts .= ",snapshot=$v";
1764 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1765 my ($dir, $qmpname) = @$type;
1766 if (my $v = $drive->{"mbps$dir"}) {
1767 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1769 if (my $v = $drive->{"mbps${dir}_max"}) {
1770 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1772 if (my $v = $drive->{"bps${dir}_max_length"}) {
1773 $opts .= ",throttling.bps$qmpname-max-length=$v";
1775 if (my $v = $drive->{"iops${dir}"}) {
1776 $opts .= ",throttling.iops$qmpname=$v";
1778 if (my $v = $drive->{"iops${dir}_max"}) {
1779 $opts .= ",throttling.iops$qmpname-max=$v";
1781 if (my $v = $drive->{"iops${dir}_max_length"}) {
1782 $opts .= ",throttling.iops$qmpname-max-length=$v";
1786 $opts .= ",format=$format" if $format && !$drive->{format
};
1788 my $cache_direct = 0;
1790 if (my $cache = $drive->{cache
}) {
1791 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1792 } elsif (!drive_is_cdrom
($drive)) {
1793 $opts .= ",cache=none";
1797 # aio native works only with O_DIRECT
1798 if (!$drive->{aio
}) {
1800 $opts .= ",aio=native";
1802 $opts .= ",aio=threads";
1806 if (!drive_is_cdrom
($drive)) {
1808 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1809 $detectzeroes = 'off';
1810 } elsif ($drive->{discard
}) {
1811 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1813 # This used to be our default with discard not being specified:
1814 $detectzeroes = 'on';
1816 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1819 my $pathinfo = $path ?
"file=$path," : '';
1821 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1824 sub print_netdevice_full
{
1825 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files) = @_;
1827 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
1829 my $device = $net->{model
};
1830 if ($net->{model
} eq 'virtio') {
1831 $device = 'virtio-net-pci';
1834 my $pciaddr = print_pci_addr
("$netid", $bridges);
1835 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1836 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1837 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1838 my $vectors = $net->{queues
} * 2 + 2;
1839 $tmpstr .= ",vectors=$vectors,mq=on";
1841 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1843 if ($use_old_bios_files) {
1845 if ($device eq 'virtio-net-pci') {
1846 $romfile = 'pxe-virtio.rom';
1847 } elsif ($device eq 'e1000') {
1848 $romfile = 'pxe-e1000.rom';
1849 } elsif ($device eq 'ne2k') {
1850 $romfile = 'pxe-ne2k_pci.rom';
1851 } elsif ($device eq 'pcnet') {
1852 $romfile = 'pxe-pcnet.rom';
1853 } elsif ($device eq 'rtl8139') {
1854 $romfile = 'pxe-rtl8139.rom';
1856 $tmpstr .= ",romfile=$romfile" if $romfile;
1862 sub print_netdev_full
{
1863 my ($vmid, $conf, $net, $netid, $hotplug) = @_;
1866 if ($netid =~ m/^net(\d+)$/) {
1870 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1872 my $ifname = "tap${vmid}i$i";
1874 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1875 die "interface name '$ifname' is too long (max 15 character)\n"
1876 if length($ifname) >= 16;
1878 my $vhostparam = '';
1879 $vhostparam = ',vhost=on' if $kernel_has_vhost_net && $net->{model
} eq 'virtio';
1881 my $vmname = $conf->{name
} || "vm$vmid";
1884 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1886 if ($net->{bridge
}) {
1887 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1889 $netdev = "type=user,id=$netid,hostname=$vmname";
1892 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1898 sub print_cpu_device
{
1899 my ($conf, $id) = @_;
1901 my $kvm = $conf->{kvm
} // 1;
1902 my $cpu = $kvm ?
"kvm64" : "qemu64";
1903 if (my $cputype = $conf->{cpu
}) {
1904 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
1905 or die "Cannot parse cpu description: $cputype\n";
1906 $cpu = $cpuconf->{cputype
};
1909 my $cores = $conf->{cores
} || 1;
1911 my $current_core = ($id - 1) % $cores;
1912 my $current_socket = int(($id - 1 - $current_core)/$cores);
1914 return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
1917 sub drive_is_cloudinit
{
1919 return $drive->{file
} =~ m
@[:/]vm-\d
+-cloudinit
(?
:\
.$QEMU_FORMAT_RE)?
$@;
1922 sub drive_is_cdrom
{
1923 my ($drive, $exclude_cloudinit) = @_;
1925 return 0 if $exclude_cloudinit && drive_is_cloudinit
($drive);
1927 return $drive && $drive->{media
} && ($drive->{media
} eq 'cdrom');
1931 sub parse_number_sets
{
1934 foreach my $part (split(/;/, $set)) {
1935 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
1936 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
1937 push @$res, [ $1, $2 ];
1939 die "invalid range: $part\n";
1948 my $res = PVE
::JSONSchema
::parse_property_string
($numa_fmt, $data);
1949 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
1950 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
1957 return undef if !$value;
1959 my $res = PVE
::JSONSchema
::parse_property_string
($hostpci_fmt, $value);
1961 my @idlist = split(/;/, $res->{host
});
1962 delete $res->{host
};
1963 foreach my $id (@idlist) {
1964 if ($id =~ /^$PCIRE$/) {
1966 push @{$res->{pciid
}}, { id
=> $1, function
=> $2 };
1968 my $pcidevices = lspci
($1);
1969 $res->{pciid
} = $pcidevices->{$1};
1972 # should have been caught by parse_property_string already
1973 die "failed to parse PCI id: $id\n";
1979 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1983 my $res = eval { PVE
::JSONSchema
::parse_property_string
($net_fmt, $data) };
1988 if (!defined($res->{macaddr
})) {
1989 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
1990 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
1995 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
1996 sub parse_ipconfig
{
1999 my $res = eval { PVE
::JSONSchema
::parse_property_string
($ipconfig_fmt, $data) };
2005 if ($res->{gw
} && !$res->{ip
}) {
2006 warn 'gateway specified without specifying an IP address';
2009 if ($res->{gw6
} && !$res->{ip6
}) {
2010 warn 'IPv6 gateway specified without specifying an IPv6 address';
2013 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
2014 warn 'gateway specified together with DHCP';
2017 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
2019 warn "IPv6 gateway specified together with $res->{ip6} address";
2023 if (!$res->{ip
} && !$res->{ip6
}) {
2024 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
2033 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
2036 sub add_random_macs
{
2037 my ($settings) = @_;
2039 foreach my $opt (keys %$settings) {
2040 next if $opt !~ m/^net(\d+)$/;
2041 my $net = parse_net
($settings->{$opt});
2043 $settings->{$opt} = print_net
($net);
2047 sub vm_is_volid_owner
{
2048 my ($storecfg, $vmid, $volid) = @_;
2050 if ($volid !~ m
|^/|) {
2052 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
2053 if ($owner && ($owner == $vmid)) {
2061 sub split_flagged_list
{
2062 my $text = shift || '';
2063 $text =~ s/[,;]/ /g;
2065 return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
2068 sub join_flagged_list
{
2069 my ($how, $lst) = @_;
2070 join $how, map { $lst->{$_} . $_ } keys %$lst;
2073 sub vmconfig_delete_pending_option
{
2074 my ($conf, $key, $force) = @_;
2076 delete $conf->{pending
}->{$key};
2077 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2078 $pending_delete_hash->{$key} = $force ?
'!' : '';
2079 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2082 sub vmconfig_undelete_pending_option
{
2083 my ($conf, $key) = @_;
2085 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2086 delete $pending_delete_hash->{$key};
2088 if (%$pending_delete_hash) {
2089 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2091 delete $conf->{pending
}->{delete};
2095 sub vmconfig_register_unused_drive
{
2096 my ($storecfg, $vmid, $conf, $drive) = @_;
2098 if (drive_is_cloudinit
($drive)) {
2099 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
2101 } elsif (!drive_is_cdrom
($drive)) {
2102 my $volid = $drive->{file
};
2103 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
2104 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
2109 sub vmconfig_cleanup_pending
{
2112 # remove pending changes when nothing changed
2114 foreach my $opt (keys %{$conf->{pending
}}) {
2115 if (defined($conf->{$opt}) && ($conf->{pending
}->{$opt} eq $conf->{$opt})) {
2117 delete $conf->{pending
}->{$opt};
2121 my $current_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2122 my $pending_delete_hash = {};
2123 while (my ($opt, $force) = each %$current_delete_hash) {
2124 if (defined($conf->{$opt})) {
2125 $pending_delete_hash->{$opt} = $force;
2131 if (%$pending_delete_hash) {
2132 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2134 delete $conf->{pending
}->{delete};
2140 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
2144 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2145 format_description
=> 'UUID',
2146 description
=> "Set SMBIOS1 UUID.",
2152 format_description
=> 'string',
2153 description
=> "Set SMBIOS1 version.",
2159 format_description
=> 'string',
2160 description
=> "Set SMBIOS1 serial number.",
2166 format_description
=> 'string',
2167 description
=> "Set SMBIOS1 manufacturer.",
2173 format_description
=> 'string',
2174 description
=> "Set SMBIOS1 product ID.",
2180 format_description
=> 'string',
2181 description
=> "Set SMBIOS1 SKU string.",
2187 format_description
=> 'string',
2188 description
=> "Set SMBIOS1 family string.",
2196 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_fmt, $data) };
2203 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
2206 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
2208 PVE
::JSONSchema
::register_format
('pve-qm-bootdisk', \
&verify_bootdisk
);
2209 sub verify_bootdisk
{
2210 my ($value, $noerr) = @_;
2212 return $value if is_valid_drivename
($value);
2214 return undef if $noerr;
2216 die "invalid boot disk '$value'\n";
2219 sub parse_watchdog
{
2222 return undef if !$value;
2224 my $res = eval { PVE
::JSONSchema
::parse_property_string
($watchdog_fmt, $value) };
2229 sub parse_guest_agent
{
2232 return {} if !defined($value->{agent
});
2234 my $res = eval { PVE
::JSONSchema
::parse_property_string
($agent_fmt, $value->{agent
}) };
2237 # if the agent is disabled ignore the other potentially set properties
2238 return {} if !$res->{enabled
};
2242 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
2243 sub verify_usb_device
{
2244 my ($value, $noerr) = @_;
2246 return $value if parse_usb_device
($value);
2248 return undef if $noerr;
2250 die "unable to parse usb device\n";
2253 # add JSON properties for create and set function
2254 sub json_config_properties
{
2257 foreach my $opt (keys %$confdesc) {
2258 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate';
2259 $prop->{$opt} = $confdesc->{$opt};
2265 # return copy of $confdesc_cloudinit to generate documentation
2266 sub cloudinit_config_properties
{
2268 return dclone
($confdesc_cloudinit);
2272 my ($key, $value) = @_;
2274 die "unknown setting '$key'\n" if !$confdesc->{$key};
2276 my $type = $confdesc->{$key}->{type
};
2278 if (!defined($value)) {
2279 die "got undefined value\n";
2282 if ($value =~ m/[\n\r]/) {
2283 die "property contains a line feed\n";
2286 if ($type eq 'boolean') {
2287 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2288 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2289 die "type check ('boolean') failed - got '$value'\n";
2290 } elsif ($type eq 'integer') {
2291 return int($1) if $value =~ m/^(\d+)$/;
2292 die "type check ('integer') failed - got '$value'\n";
2293 } elsif ($type eq 'number') {
2294 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2295 die "type check ('number') failed - got '$value'\n";
2296 } elsif ($type eq 'string') {
2297 if (my $fmt = $confdesc->{$key}->{format
}) {
2298 PVE
::JSONSchema
::check_format
($fmt, $value);
2301 $value =~ s/^\"(.*)\"$/$1/;
2304 die "internal error"
2308 sub check_iommu_support
{
2309 #fixme : need to check IOMMU support
2310 #http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM
2320 my $conf = PVE
::QemuConfig-
>config_file($vmid);
2321 utime undef, undef, $conf;
2325 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
2327 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
2329 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2331 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2333 if ($conf->{template
}) {
2334 # check if any base image is still used by a linked clone
2335 foreach_drive
($conf, sub {
2336 my ($ds, $drive) = @_;
2338 return if drive_is_cdrom
($drive);
2340 my $volid = $drive->{file
};
2342 return if !$volid || $volid =~ m
|^/|;
2344 die "base volume '$volid' is still in use by linked cloned\n"
2345 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2350 # only remove disks owned by this VM
2351 foreach_drive
($conf, sub {
2352 my ($ds, $drive) = @_;
2354 return if drive_is_cdrom
($drive, 1);
2356 my $volid = $drive->{file
};
2358 return if !$volid || $volid =~ m
|^/|;
2360 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2361 return if !$path || !$owner || ($owner != $vmid);
2364 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2366 warn "Could not remove disk '$volid', check manually: $@" if $@;
2370 if ($keep_empty_config) {
2371 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
2376 # also remove unused disk
2378 my $dl = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
2381 PVE
::Storage
::foreach_volid
($dl, sub {
2382 my ($volid, $sid, $volname, $d) = @_;
2383 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2392 sub parse_vm_config
{
2393 my ($filename, $raw) = @_;
2395 return undef if !defined($raw);
2398 digest
=> Digest
::SHA
::sha1_hex
($raw),
2403 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2404 || die "got strange filename '$filename'";
2412 my @lines = split(/\n/, $raw);
2413 foreach my $line (@lines) {
2414 next if $line =~ m/^\s*$/;
2416 if ($line =~ m/^\[PENDING\]\s*$/i) {
2417 $section = 'pending';
2418 if (defined($descr)) {
2420 $conf->{description
} = $descr;
2423 $conf = $res->{$section} = {};
2426 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2428 if (defined($descr)) {
2430 $conf->{description
} = $descr;
2433 $conf = $res->{snapshots
}->{$section} = {};
2437 if ($line =~ m/^\#(.*)\s*$/) {
2438 $descr = '' if !defined($descr);
2439 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2443 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2444 $descr = '' if !defined($descr);
2445 $descr .= PVE
::Tools
::decode_text
($2);
2446 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2447 $conf->{snapstate
} = $1;
2448 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2451 $conf->{$key} = $value;
2452 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2454 if ($section eq 'pending') {
2455 $conf->{delete} = $value; # we parse this later
2457 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2459 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2462 eval { $value = check_type
($key, $value); };
2464 warn "vm $vmid - unable to parse value of '$key' - $@";
2466 $key = 'ide2' if $key eq 'cdrom';
2467 my $fmt = $confdesc->{$key}->{format
};
2468 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2469 my $v = parse_drive
($key, $value);
2470 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2471 $v->{file
} = $volid;
2472 $value = print_drive
($vmid, $v);
2474 warn "vm $vmid - unable to parse value of '$key'\n";
2479 $conf->{$key} = $value;
2484 if (defined($descr)) {
2486 $conf->{description
} = $descr;
2488 delete $res->{snapstate
}; # just to be sure
2493 sub write_vm_config
{
2494 my ($filename, $conf) = @_;
2496 delete $conf->{snapstate
}; # just to be sure
2498 if ($conf->{cdrom
}) {
2499 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2500 $conf->{ide2
} = $conf->{cdrom
};
2501 delete $conf->{cdrom
};
2504 # we do not use 'smp' any longer
2505 if ($conf->{sockets
}) {
2506 delete $conf->{smp
};
2507 } elsif ($conf->{smp
}) {
2508 $conf->{sockets
} = $conf->{smp
};
2509 delete $conf->{cores
};
2510 delete $conf->{smp
};
2513 my $used_volids = {};
2515 my $cleanup_config = sub {
2516 my ($cref, $pending, $snapname) = @_;
2518 foreach my $key (keys %$cref) {
2519 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2520 $key eq 'snapstate' || $key eq 'pending';
2521 my $value = $cref->{$key};
2522 if ($key eq 'delete') {
2523 die "propertry 'delete' is only allowed in [PENDING]\n"
2525 # fixme: check syntax?
2528 eval { $value = check_type
($key, $value); };
2529 die "unable to parse value of '$key' - $@" if $@;
2531 $cref->{$key} = $value;
2533 if (!$snapname && is_valid_drivename
($key)) {
2534 my $drive = parse_drive
($key, $value);
2535 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2540 &$cleanup_config($conf);
2542 &$cleanup_config($conf->{pending
}, 1);
2544 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2545 die "internal error" if $snapname eq 'pending';
2546 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2549 # remove 'unusedX' settings if we re-add a volume
2550 foreach my $key (keys %$conf) {
2551 my $value = $conf->{$key};
2552 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2553 delete $conf->{$key};
2557 my $generate_raw_config = sub {
2558 my ($conf, $pending) = @_;
2562 # add description as comment to top of file
2563 if (defined(my $descr = $conf->{description
})) {
2565 foreach my $cl (split(/\n/, $descr)) {
2566 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2569 $raw .= "#\n" if $pending;
2573 foreach my $key (sort keys %$conf) {
2574 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2575 $raw .= "$key: $conf->{$key}\n";
2580 my $raw = &$generate_raw_config($conf);
2582 if (scalar(keys %{$conf->{pending
}})){
2583 $raw .= "\n[PENDING]\n";
2584 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2587 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2588 $raw .= "\n[$snapname]\n";
2589 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2599 # we use static defaults from our JSON schema configuration
2600 foreach my $key (keys %$confdesc) {
2601 if (defined(my $default = $confdesc->{$key}->{default})) {
2602 $res->{$key} = $default;
2610 my $vmlist = PVE
::Cluster
::get_vmlist
();
2612 return $res if !$vmlist || !$vmlist->{ids
};
2613 my $ids = $vmlist->{ids
};
2615 foreach my $vmid (keys %$ids) {
2616 my $d = $ids->{$vmid};
2617 next if !$d->{node
} || $d->{node
} ne $nodename;
2618 next if !$d->{type
} || $d->{type
} ne 'qemu';
2619 $res->{$vmid}->{exists} = 1;
2624 # test if VM uses local resources (to prevent migration)
2625 sub check_local_resources
{
2626 my ($conf, $noerr) = @_;
2630 $loc_res = 1 if $conf->{hostusb
}; # old syntax
2631 $loc_res = 1 if $conf->{hostpci
}; # old syntax
2633 foreach my $k (keys %$conf) {
2634 next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2635 # sockets are safe: they will recreated be on the target side post-migrate
2636 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2637 $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2640 die "VM uses local resources\n" if $loc_res && !$noerr;
2645 # check if used storages are available on all nodes (use by migrate)
2646 sub check_storage_availability
{
2647 my ($storecfg, $conf, $node) = @_;
2649 foreach_drive
($conf, sub {
2650 my ($ds, $drive) = @_;
2652 my $volid = $drive->{file
};
2655 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2658 # check if storage is available on both nodes
2659 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2660 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2664 # list nodes where all VM images are available (used by has_feature API)
2666 my ($conf, $storecfg) = @_;
2668 my $nodelist = PVE
::Cluster
::get_nodelist
();
2669 my $nodehash = { map { $_ => 1 } @$nodelist };
2670 my $nodename = PVE
::INotify
::nodename
();
2672 foreach_drive
($conf, sub {
2673 my ($ds, $drive) = @_;
2675 my $volid = $drive->{file
};
2678 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2680 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2681 if ($scfg->{disable
}) {
2683 } elsif (my $avail = $scfg->{nodes
}) {
2684 foreach my $node (keys %$nodehash) {
2685 delete $nodehash->{$node} if !$avail->{$node};
2687 } elsif (!$scfg->{shared
}) {
2688 foreach my $node (keys %$nodehash) {
2689 delete $nodehash->{$node} if $node ne $nodename
2699 my ($pidfile, $pid) = @_;
2701 my $fh = IO
::File-
>new("/proc/$pid/cmdline", "r");
2705 return undef if !$line;
2706 my @param = split(/\0/, $line);
2708 my $cmd = $param[0];
2709 return if !$cmd || ($cmd !~ m
|kvm
$| && $cmd !~ m
|qemu-system-x86_64
$|);
2711 for (my $i = 0; $i < scalar (@param); $i++) {
2714 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2715 my $p = $param[$i+1];
2716 return 1 if $p && ($p eq $pidfile);
2725 my ($vmid, $nocheck, $node) = @_;
2727 my $filename = PVE
::QemuConfig-
>config_file($vmid, $node);
2729 die "unable to find configuration file for VM $vmid - no such machine\n"
2730 if !$nocheck && ! -f
$filename;
2732 my $pidfile = pidfile_name
($vmid);
2734 if (my $fd = IO
::File-
>new("<$pidfile")) {
2739 my $mtime = $st->mtime;
2740 if ($mtime > time()) {
2741 warn "file '$filename' modified in future\n";
2744 if ($line =~ m/^(\d+)$/) {
2746 if (check_cmdline
($pidfile, $pid)) {
2747 if (my $pinfo = PVE
::ProcFSTools
::check_process_running
($pid)) {
2759 my $vzlist = config_list
();
2761 my $fd = IO
::Dir-
>new($var_run_tmpdir) || return $vzlist;
2763 while (defined(my $de = $fd->read)) {
2764 next if $de !~ m/^(\d+)\.pid$/;
2766 next if !defined($vzlist->{$vmid});
2767 if (my $pid = check_running
($vmid)) {
2768 $vzlist->{$vmid}->{pid
} = $pid;
2776 my ($storecfg, $conf) = @_;
2778 my $bootdisk = $conf->{bootdisk
};
2779 return undef if !$bootdisk;
2780 return undef if !is_valid_drivename
($bootdisk);
2782 return undef if !$conf->{$bootdisk};
2784 my $drive = parse_drive
($bootdisk, $conf->{$bootdisk});
2785 return undef if !defined($drive);
2787 return undef if drive_is_cdrom
($drive);
2789 my $volid = $drive->{file
};
2790 return undef if !$volid;
2792 return $drive->{size
};
2795 our $vmstatus_return_properties = {
2796 vmid
=> get_standard_option
('pve-vmid'),
2798 description
=> "Qemu process status.",
2800 enum
=> ['stopped', 'running'],
2803 description
=> "Maximum memory in bytes.",
2806 renderer
=> 'bytes',
2809 description
=> "Root disk size in bytes.",
2812 renderer
=> 'bytes',
2815 description
=> "VM name.",
2820 description
=> "Qemu QMP agent status.",
2825 description
=> "PID of running qemu process.",
2830 description
=> "Uptime.",
2833 renderer
=> 'duration',
2836 description
=> "Maximum usable CPUs.",
2842 my $last_proc_pid_stat;
2844 # get VM status information
2845 # This must be fast and should not block ($full == false)
2846 # We only query KVM using QMP if $full == true (this can be slow)
2848 my ($opt_vmid, $full) = @_;
2852 my $storecfg = PVE
::Storage
::config
();
2854 my $list = vzlist
();
2855 my $defaults = load_defaults
();
2857 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2859 my $cpucount = $cpuinfo->{cpus
} || 1;
2861 foreach my $vmid (keys %$list) {
2862 next if $opt_vmid && ($vmid ne $opt_vmid);
2864 my $cfspath = PVE
::QemuConfig-
>cfs_config_path($vmid);
2865 my $conf = PVE
::Cluster
::cfs_read_file
($cfspath) || {};
2867 my $d = { vmid
=> $vmid };
2868 $d->{pid
} = $list->{$vmid}->{pid
};
2870 # fixme: better status?
2871 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
2873 my $size = disksize
($storecfg, $conf);
2874 if (defined($size)) {
2875 $d->{disk
} = 0; # no info available
2876 $d->{maxdisk
} = $size;
2882 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
2883 * ($conf->{cores
} || $defaults->{cores
});
2884 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
2885 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
2887 $d->{name
} = $conf->{name
} || "VM $vmid";
2888 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
2889 : $defaults->{memory
}*(1024*1024);
2891 if ($conf->{balloon
}) {
2892 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
2893 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
2894 : $defaults->{shares
};
2905 $d->{diskwrite
} = 0;
2907 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
2909 $d->{serial
} = 1 if conf_has_serial
($conf);
2914 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
2915 foreach my $dev (keys %$netdev) {
2916 next if $dev !~ m/^tap([1-9]\d*)i/;
2918 my $d = $res->{$vmid};
2921 $d->{netout
} += $netdev->{$dev}->{receive
};
2922 $d->{netin
} += $netdev->{$dev}->{transmit
};
2925 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
2926 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
2931 my $ctime = gettimeofday
;
2933 foreach my $vmid (keys %$list) {
2935 my $d = $res->{$vmid};
2936 my $pid = $d->{pid
};
2939 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
2940 next if !$pstat; # not running
2942 my $used = $pstat->{utime} + $pstat->{stime
};
2944 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
2946 if ($pstat->{vsize
}) {
2947 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
2950 my $old = $last_proc_pid_stat->{$pid};
2952 $last_proc_pid_stat->{$pid} = {
2960 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
2962 if ($dtime > 1000) {
2963 my $dutime = $used - $old->{used
};
2965 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
2966 $last_proc_pid_stat->{$pid} = {
2972 $d->{cpu
} = $old->{cpu
};
2976 return $res if !$full;
2978 my $qmpclient = PVE
::QMPClient-
>new();
2980 my $ballooncb = sub {
2981 my ($vmid, $resp) = @_;
2983 my $info = $resp->{'return'};
2984 return if !$info->{max_mem
};
2986 my $d = $res->{$vmid};
2988 # use memory assigned to VM
2989 $d->{maxmem
} = $info->{max_mem
};
2990 $d->{balloon
} = $info->{actual
};
2992 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
2993 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
2994 $d->{freemem
} = $info->{free_mem
};
2997 $d->{ballooninfo
} = $info;
3000 my $blockstatscb = sub {
3001 my ($vmid, $resp) = @_;
3002 my $data = $resp->{'return'} || [];
3003 my $totalrdbytes = 0;
3004 my $totalwrbytes = 0;
3006 for my $blockstat (@$data) {
3007 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
3008 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
3010 $blockstat->{device
} =~ s/drive-//;
3011 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
3013 $res->{$vmid}->{diskread
} = $totalrdbytes;
3014 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
3017 my $statuscb = sub {
3018 my ($vmid, $resp) = @_;
3020 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
3021 # this fails if ballon driver is not loaded, so this must be
3022 # the last commnand (following command are aborted if this fails).
3023 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
3025 my $status = 'unknown';
3026 if (!defined($status = $resp->{'return'}->{status
})) {
3027 warn "unable to get VM status\n";
3031 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
3034 foreach my $vmid (keys %$list) {
3035 next if $opt_vmid && ($vmid ne $opt_vmid);
3036 next if !$res->{$vmid}->{pid
}; # not running
3037 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
3040 $qmpclient->queue_execute(undef, 2);
3042 foreach my $vmid (keys %$list) {
3043 next if $opt_vmid && ($vmid ne $opt_vmid);
3044 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
3051 my ($conf, $func, @param) = @_;
3053 foreach my $ds (valid_drive_names
()) {
3054 next if !defined($conf->{$ds});
3056 my $drive = parse_drive
($ds, $conf->{$ds});
3059 &$func($ds, $drive, @param);
3064 my ($conf, $func, @param) = @_;
3068 my $test_volid = sub {
3069 my ($volid, $is_cdrom, $replicate, $shared, $snapname) = @_;
3073 $volhash->{$volid}->{cdrom
} //= 1;
3074 $volhash->{$volid}->{cdrom
} = 0 if !$is_cdrom;
3076 $volhash->{$volid}->{replicate
} //= 0;
3077 $volhash->{$volid}->{replicate
} = 1 if $replicate;
3079 $volhash->{$volid}->{shared
} //= 0;
3080 $volhash->{$volid}->{shared
} = 1 if $shared;
3082 $volhash->{$volid}->{referenced_in_config
} //= 0;
3083 $volhash->{$volid}->{referenced_in_config
} = 1 if !defined($snapname);
3085 $volhash->{$volid}->{referenced_in_snapshot
}->{$snapname} = 1
3086 if defined($snapname);
3089 foreach_drive
($conf, sub {
3090 my ($ds, $drive) = @_;
3091 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, undef);
3094 foreach my $snapname (keys %{$conf->{snapshots
}}) {
3095 my $snap = $conf->{snapshots
}->{$snapname};
3096 $test_volid->($snap->{vmstate
}, 0, 1, $snapname);
3097 foreach_drive
($snap, sub {
3098 my ($ds, $drive) = @_;
3099 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, $snapname);
3103 foreach my $volid (keys %$volhash) {
3104 &$func($volid, $volhash->{$volid}, @param);
3108 sub conf_has_serial
{
3111 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3112 if ($conf->{"serial$i"}) {
3120 sub vga_conf_has_spice
{
3123 return 0 if !$vga || $vga !~ m/^qxl([234])?$/;
3128 sub config_to_command
{
3129 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
3132 my $globalFlags = [];
3133 my $machineFlags = [];
3139 my $kvmver = kvm_user_version
();
3140 my $vernum = 0; # unknown
3141 my $ostype = $conf->{ostype
};
3142 my $winversion = windows_version
($ostype);
3143 my $kvm = $conf->{kvm
} // 1;
3145 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n" if (!$cpuinfo->{hvm
} && $kvm);
3147 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
3148 $vernum = $1*1000000+$2*1000;
3149 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
3150 $vernum = $1*1000000+$2*1000+$3;
3153 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
3155 my $have_ovz = -f
'/proc/vz/vestat';
3157 my $q35 = machine_type_is_q35
($conf);
3158 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3159 my $machine_type = $forcemachine || $conf->{machine
};
3160 my $use_old_bios_files = undef;
3161 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3163 my $cpuunits = defined($conf->{cpuunits
}) ?
3164 $conf->{cpuunits
} : $defaults->{cpuunits
};
3166 push @$cmd, '/usr/bin/kvm';
3168 push @$cmd, '-id', $vmid;
3170 my $vmname = $conf->{name
} || "vm$vmid";
3172 push @$cmd, '-name', $vmname;
3176 my $qmpsocket = qmp_socket
($vmid);
3177 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3178 push @$cmd, '-mon', "chardev=qmp,mode=control";
3181 push @$cmd, '-pidfile' , pidfile_name
($vmid);
3183 push @$cmd, '-daemonize';
3185 if ($conf->{smbios1
}) {
3186 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3189 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3190 die "uefi base image not found\n" if ! -f
$OVMF_CODE;
3194 if (my $efidisk = $conf->{efidisk0
}) {
3195 my $d = PVE
::JSONSchema
::parse_property_string
($efidisk_fmt, $efidisk);
3196 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3197 $format = $d->{format
};
3199 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3200 if (!defined($format)) {
3201 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3202 $format = qemu_img_format
($scfg, $volname);
3206 die "efidisk format must be specified\n"
3207 if !defined($format);
3210 warn "no efidisk configured! Using temporary efivars disk.\n";
3211 $path = "/tmp/$vmid-ovmf.fd";
3212 PVE
::Tools
::file_copy
($OVMF_VARS, $path, -s
$OVMF_VARS);
3216 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$OVMF_CODE";
3217 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
3221 # add usb controllers
3222 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $q35, $usbdesc->{format
}, $MAX_USB_DEVICES);
3223 push @$devices, @usbcontrollers if @usbcontrollers;
3224 my $vga = $conf->{vga
};
3226 my $qxlnum = vga_conf_has_spice
($vga);
3227 $vga = 'qxl' if $qxlnum;
3230 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 9)) {
3231 $vga = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3233 $vga = ($winversion >= 6) ?
'std' : 'cirrus';
3237 # enable absolute mouse coordinates (needed by vnc)
3239 if (defined($conf->{tablet
})) {
3240 $tablet = $conf->{tablet
};
3242 $tablet = $defaults->{tablet
};
3243 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3244 $tablet = 0 if $vga =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3247 push @$devices, '-device', print_tabletdevice_full
($conf) if $tablet;
3250 my $gpu_passthrough;
3253 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3254 my $d = parse_hostpci
($conf->{"hostpci$i"});
3257 my $pcie = $d->{pcie
};
3259 die "q35 machine model is not enabled" if !$q35;
3260 $pciaddr = print_pcie_addr
("hostpci$i");
3262 $pciaddr = print_pci_addr
("hostpci$i", $bridges);
3265 my $rombar = defined($d->{rombar
}) && !$d->{rombar
} ?
',rombar=0' : '';
3266 my $romfile = $d->{romfile
};
3269 if ($d->{'x-vga'}) {
3270 $xvga = ',x-vga=on';
3273 $gpu_passthrough = 1;
3275 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3279 my $pcidevices = $d->{pciid
};
3280 my $multifunction = 1 if @$pcidevices > 1;
3283 foreach my $pcidevice (@$pcidevices) {
3285 my $id = "hostpci$i";
3286 $id .= ".$j" if $multifunction;
3287 my $addr = $pciaddr;
3288 $addr .= ".$j" if $multifunction;
3289 my $devicestr = "vfio-pci,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
3292 $devicestr .= "$rombar$xvga";
3293 $devicestr .= ",multifunction=on" if $multifunction;
3294 $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
3297 push @$devices, '-device', $devicestr;
3303 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES);
3304 push @$devices, @usbdevices if @usbdevices;
3306 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3307 if (my $path = $conf->{"serial$i"}) {
3308 if ($path eq 'socket') {
3309 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3310 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3311 push @$devices, '-device', "isa-serial,chardev=serial$i";
3313 die "no such serial device\n" if ! -c
$path;
3314 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3315 push @$devices, '-device', "isa-serial,chardev=serial$i";
3321 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3322 if (my $path = $conf->{"parallel$i"}) {
3323 die "no such parallel device\n" if ! -c
$path;
3324 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3325 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3326 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3332 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3333 $sockets = $conf->{sockets
} if $conf->{sockets
};
3335 my $cores = $conf->{cores
} || 1;
3337 my $maxcpus = $sockets * $cores;
3339 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3341 my $allowed_vcpus = $cpuinfo->{cpus
};
3343 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3344 if ($allowed_vcpus < $maxcpus);
3346 if($hotplug_features->{cpu
} && qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 7)) {
3348 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3349 for (my $i = 2; $i <= $vcpus; $i++) {
3350 my $cpustr = print_cpu_device
($conf,$i);
3351 push @$cmd, '-device', $cpustr;
3356 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3358 push @$cmd, '-nodefaults';
3360 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3362 my $bootindex_hash = {};
3364 foreach my $o (split(//, $bootorder)) {
3365 $bootindex_hash->{$o} = $i*100;
3369 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3371 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3373 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3375 push @$cmd, '-vga', $vga if $vga && $vga !~ m/^serial\d+$/; # for kvm 77 and later
3377 if ($vga && $vga !~ m/^serial\d+$/ && $vga ne 'none'){
3378 my $socket = vnc_socket
($vmid);
3379 push @$cmd, '-vnc', "unix:$socket,x509,password";
3381 push @$cmd, '-nographic';
3385 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3387 my $useLocaltime = $conf->{localtime};
3389 if ($winversion >= 5) { # windows
3390 $useLocaltime = 1 if !defined($conf->{localtime});
3392 # use time drift fix when acpi is enabled
3393 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3394 $tdf = 1 if !defined($conf->{tdf
});
3398 if ($winversion >= 6) {
3399 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3400 push @$cmd, '-no-hpet';
3403 push @$rtcFlags, 'driftfix=slew' if $tdf;
3406 push @$machineFlags, 'accel=tcg';
3409 if ($machine_type) {
3410 push @$machineFlags, "type=${machine_type}";
3413 if ($conf->{startdate
}) {
3414 push @$rtcFlags, "base=$conf->{startdate}";
3415 } elsif ($useLocaltime) {
3416 push @$rtcFlags, 'base=localtime';
3419 my $cpu = $kvm ?
"kvm64" : "qemu64";
3420 if (my $cputype = $conf->{cpu
}) {
3421 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
3422 or die "Cannot parse cpu description: $cputype\n";
3423 $cpu = $cpuconf->{cputype
};
3424 $kvm_off = 1 if $cpuconf->{hidden
};
3426 if (defined(my $flags = $cpuconf->{flags
})) {
3427 push @$cpuFlags, split(";", $flags);
3431 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64';
3433 push @$cpuFlags , '-x2apic'
3434 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3436 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3438 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3440 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3442 push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
3443 push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
3446 add_hyperv_enlightenments
($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios
}, $gpu_passthrough) if $kvm;
3448 push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm;
3450 push @$cpuFlags, 'kvm=off' if $kvm_off;
3452 my $cpu_vendor = $cpu_vendor_list->{$cpu} ||
3453 die "internal error"; # should not happen
3455 push @$cpuFlags, "vendor=${cpu_vendor}"
3456 if $cpu_vendor ne 'default';
3458 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3460 push @$cmd, '-cpu', $cpu;
3462 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3464 push @$cmd, '-S' if $conf->{freeze
};
3466 push @$cmd, '-k', $conf->{keyboard
} if defined($conf->{keyboard
});
3469 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3470 #push @$cmd, '-soundhw', 'es1370';
3471 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3473 if (parse_guest_agent
($conf)->{enabled
}) {
3474 my $qgasocket = qmp_socket
($vmid, 1);
3475 my $pciaddr = print_pci_addr
("qga0", $bridges);
3476 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3477 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3478 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3486 for(my $i = 1; $i < $qxlnum; $i++){
3487 my $pciaddr = print_pci_addr
("vga$i", $bridges);
3488 push @$devices, '-device', "qxl,id=vga$i,ram_size=67108864,vram_size=33554432$pciaddr";
3491 # assume other OS works like Linux
3492 push @$cmd, '-global', 'qxl-vga.ram_size=134217728';
3493 push @$cmd, '-global', 'qxl-vga.vram_size=67108864';
3497 my $pciaddr = print_pci_addr
("spice", $bridges);
3499 my $nodename = PVE
::INotify
::nodename
();
3500 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3501 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3502 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3503 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3504 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3506 push @$devices, '-spice', "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3508 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3509 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3510 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3513 # enable balloon by default, unless explicitly disabled
3514 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3515 $pciaddr = print_pci_addr
("balloon0", $bridges);
3516 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3519 if ($conf->{watchdog
}) {
3520 my $wdopts = parse_watchdog
($conf->{watchdog
});
3521 $pciaddr = print_pci_addr
("watchdog", $bridges);
3522 my $watchdog = $wdopts->{model
} || 'i6300esb';
3523 push @$devices, '-device', "$watchdog$pciaddr";
3524 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3528 my $scsicontroller = {};
3529 my $ahcicontroller = {};
3530 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3532 # Add iscsi initiator name if available
3533 if (my $initiator = get_initiator_name
()) {
3534 push @$devices, '-iscsi', "initiator-name=$initiator";
3537 foreach_drive
($conf, sub {
3538 my ($ds, $drive) = @_;
3540 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3541 push @$vollist, $drive->{file
};
3544 # ignore efidisk here, already added in bios/fw handling code above
3545 return if $drive->{interface
} eq 'efidisk';
3547 $use_virtio = 1 if $ds =~ m/^virtio/;
3549 if (drive_is_cdrom
($drive)) {
3550 if ($bootindex_hash->{d
}) {
3551 $drive->{bootindex
} = $bootindex_hash->{d
};
3552 $bootindex_hash->{d
} += 1;
3555 if ($bootindex_hash->{c
}) {
3556 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3557 $bootindex_hash->{c
} += 1;
3561 if($drive->{interface
} eq 'virtio'){
3562 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3565 if ($drive->{interface
} eq 'scsi') {
3567 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3569 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges);
3570 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3573 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3574 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3575 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3576 } elsif ($drive->{iothread
}) {
3577 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3581 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3582 $queues = ",num_queues=$drive->{queues}";
3585 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3586 $scsicontroller->{$controller}=1;
3589 if ($drive->{interface
} eq 'sata') {
3590 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3591 $pciaddr = print_pci_addr
("ahci$controller", $bridges);
3592 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3593 $ahcicontroller->{$controller}=1;
3596 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3597 push @$devices, '-drive',$drive_cmd;
3598 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges);
3601 for (my $i = 0; $i < $MAX_NETS; $i++) {
3602 next if !$conf->{"net$i"};
3603 my $d = parse_net
($conf->{"net$i"});
3606 $use_virtio = 1 if $d->{model
} eq 'virtio';
3608 if ($bootindex_hash->{n
}) {
3609 $d->{bootindex
} = $bootindex_hash->{n
};
3610 $bootindex_hash->{n
} += 1;
3613 my $netdevfull = print_netdev_full
($vmid,$conf,$d,"net$i");
3614 push @$devices, '-netdev', $netdevfull;
3616 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files);
3617 push @$devices, '-device', $netdevicefull;
3622 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3627 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3629 while (my ($k, $v) = each %$bridges) {
3630 $pciaddr = print_pci_addr
("pci.$k");
3631 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3636 if ($conf->{args
}) {
3637 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3641 push @$cmd, @$devices;
3642 push @$cmd, '-rtc', join(',', @$rtcFlags)
3643 if scalar(@$rtcFlags);
3644 push @$cmd, '-machine', join(',', @$machineFlags)
3645 if scalar(@$machineFlags);
3646 push @$cmd, '-global', join(',', @$globalFlags)
3647 if scalar(@$globalFlags);
3649 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3654 return "${var_run_tmpdir}/$vmid.vnc";
3660 my $res = vm_mon_cmd
($vmid, 'query-spice');
3662 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3666 my ($vmid, $qga) = @_;
3667 my $sockettype = $qga ?
'qga' : 'qmp';
3668 return "${var_run_tmpdir}/$vmid.$sockettype";
3673 return "${var_run_tmpdir}/$vmid.pid";
3676 sub vm_devices_list
{
3679 my $res = vm_mon_cmd
($vmid, 'query-pci');
3680 my $devices_to_check = [];
3682 foreach my $pcibus (@$res) {
3683 push @$devices_to_check, @{$pcibus->{devices
}},
3686 while (@$devices_to_check) {
3688 for my $d (@$devices_to_check) {
3689 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
3690 next if !$d->{'pci_bridge'};
3692 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices
}});
3693 push @$to_check, @{$d->{'pci_bridge'}->{devices
}};
3695 $devices_to_check = $to_check;
3698 my $resblock = vm_mon_cmd
($vmid, 'query-block');
3699 foreach my $block (@$resblock) {
3700 if($block->{device
} =~ m/^drive-(\S+)/){
3705 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
3706 foreach my $mice (@$resmice) {
3707 if ($mice->{name
} eq 'QEMU HID Tablet') {
3708 $devices->{tablet
} = 1;
3713 # for usb devices there is no query-usb
3714 # but we can iterate over the entries in
3715 # qom-list path=/machine/peripheral
3716 my $resperipheral = vm_mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3717 foreach my $per (@$resperipheral) {
3718 if ($per->{name
} =~ m/^usb\d+$/) {
3719 $devices->{$per->{name
}} = 1;
3727 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
3729 my $q35 = machine_type_is_q35
($conf);
3731 my $devices_list = vm_devices_list
($vmid);
3732 return 1 if defined($devices_list->{$deviceid});
3734 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid); # add PCI bridge if we need it for the device
3736 if ($deviceid eq 'tablet') {
3738 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf));
3740 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3742 die "usb hotplug currently not reliable\n";
3743 # since we can't reliably hot unplug all added usb devices
3744 # and usb passthrough disables live migration
3745 # we disable usb hotplugging for now
3746 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
3748 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3750 qemu_iothread_add
($vmid, $deviceid, $device);
3752 qemu_driveadd
($storecfg, $vmid, $device);
3753 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3755 qemu_deviceadd
($vmid, $devicefull);
3756 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3758 eval { qemu_drivedel
($vmid, $deviceid); };
3763 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3766 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
3767 my $pciaddr = print_pci_addr
($deviceid);
3768 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
3770 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
3772 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
3773 qemu_iothread_add
($vmid, $deviceid, $device);
3774 $devicefull .= ",iothread=iothread-$deviceid";
3777 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
3778 $devicefull .= ",num_queues=$device->{queues}";
3781 qemu_deviceadd
($vmid, $devicefull);
3782 qemu_deviceaddverify
($vmid, $deviceid);
3784 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3786 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device);
3787 qemu_driveadd
($storecfg, $vmid, $device);
3789 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3790 eval { qemu_deviceadd
($vmid, $devicefull); };
3792 eval { qemu_drivedel
($vmid, $deviceid); };
3797 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3799 return undef if !qemu_netdevadd
($vmid, $conf, $device, $deviceid);
3801 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
3802 my $use_old_bios_files = undef;
3803 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3805 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files);
3806 qemu_deviceadd
($vmid, $netdevicefull);
3807 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3809 eval { qemu_netdevdel
($vmid, $deviceid); };
3814 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
3817 my $pciaddr = print_pci_addr
($deviceid);
3818 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
3820 qemu_deviceadd
($vmid, $devicefull);
3821 qemu_deviceaddverify
($vmid, $deviceid);
3824 die "can't hotplug device '$deviceid'\n";
3830 # fixme: this should raise exceptions on error!
3831 sub vm_deviceunplug
{
3832 my ($vmid, $conf, $deviceid) = @_;
3834 my $devices_list = vm_devices_list
($vmid);
3835 return 1 if !defined($devices_list->{$deviceid});
3837 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
3839 if ($deviceid eq 'tablet') {
3841 qemu_devicedel
($vmid, $deviceid);
3843 } elsif ($deviceid =~ m/^usb\d+$/) {
3845 die "usb hotplug currently not reliable\n";
3846 # when unplugging usb devices this way,
3847 # there may be remaining usb controllers/hubs
3848 # so we disable it for now
3849 qemu_devicedel
($vmid, $deviceid);
3850 qemu_devicedelverify
($vmid, $deviceid);
3852 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3854 qemu_devicedel
($vmid, $deviceid);
3855 qemu_devicedelverify
($vmid, $deviceid);
3856 qemu_drivedel
($vmid, $deviceid);
3857 qemu_iothread_del
($conf, $vmid, $deviceid);
3859 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3861 qemu_devicedel
($vmid, $deviceid);
3862 qemu_devicedelverify
($vmid, $deviceid);
3863 qemu_iothread_del
($conf, $vmid, $deviceid);
3865 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3867 qemu_devicedel
($vmid, $deviceid);
3868 qemu_drivedel
($vmid, $deviceid);
3869 qemu_deletescsihw
($conf, $vmid, $deviceid);
3871 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3873 qemu_devicedel
($vmid, $deviceid);
3874 qemu_devicedelverify
($vmid, $deviceid);
3875 qemu_netdevdel
($vmid, $deviceid);
3878 die "can't unplug device '$deviceid'\n";
3884 sub qemu_deviceadd
{
3885 my ($vmid, $devicefull) = @_;
3887 $devicefull = "driver=".$devicefull;
3888 my %options = split(/[=,]/, $devicefull);
3890 vm_mon_cmd
($vmid, "device_add" , %options);
3893 sub qemu_devicedel
{
3894 my ($vmid, $deviceid) = @_;
3896 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
3899 sub qemu_iothread_add
{
3900 my($vmid, $deviceid, $device) = @_;
3902 if ($device->{iothread
}) {
3903 my $iothreads = vm_iothreads_list
($vmid);
3904 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
3908 sub qemu_iothread_del
{
3909 my($conf, $vmid, $deviceid) = @_;
3911 my $device = parse_drive
($deviceid, $conf->{$deviceid});
3912 if ($device->{iothread
}) {
3913 my $iothreads = vm_iothreads_list
($vmid);
3914 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
3918 sub qemu_objectadd
{
3919 my($vmid, $objectid, $qomtype) = @_;
3921 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
3926 sub qemu_objectdel
{
3927 my($vmid, $objectid) = @_;
3929 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
3935 my ($storecfg, $vmid, $device) = @_;
3937 my $drive = print_drive_full
($storecfg, $vmid, $device);
3938 $drive =~ s/\\/\\\\/g;
3939 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
3941 # If the command succeeds qemu prints: "OK
"
3942 return 1 if $ret =~ m/OK/s;
3944 die "adding drive failed
: $ret\n";
3948 my($vmid, $deviceid) = @_;
3950 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
3953 return 1 if $ret eq "";
3955 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
3956 return 1 if $ret =~ m/Device \'.*?\' not found/s;
3958 die "deleting drive
$deviceid failed
: $ret\n";
3961 sub qemu_deviceaddverify {
3962 my ($vmid, $deviceid) = @_;
3964 for (my $i = 0; $i <= 5; $i++) {
3965 my $devices_list = vm_devices_list($vmid);
3966 return 1 if defined($devices_list->{$deviceid});
3970 die "error on hotplug device
'$deviceid'\n";
3974 sub qemu_devicedelverify {
3975 my ($vmid, $deviceid) = @_;
3977 # need to verify that the device is correctly removed as device_del
3978 # is async and empty return is not reliable
3980 for (my $i = 0; $i <= 5; $i++) {
3981 my $devices_list = vm_devices_list($vmid);
3982 return 1 if !defined($devices_list->{$deviceid});
3986 die "error on hot-unplugging device
'$deviceid'\n";
3989 sub qemu_findorcreatescsihw {
3990 my ($storecfg, $conf, $vmid, $device) = @_;
3992 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3994 my $scsihwid="$controller_prefix$controller";
3995 my $devices_list = vm_devices_list($vmid);
3997 if(!defined($devices_list->{$scsihwid})) {
3998 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device);
4004 sub qemu_deletescsihw {
4005 my ($conf, $vmid, $opt) = @_;
4007 my $device = parse_drive($opt, $conf->{$opt});
4009 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
4010 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
4014 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4016 my $devices_list = vm_devices_list($vmid);
4017 foreach my $opt (keys %{$devices_list}) {
4018 if (PVE::QemuServer::is_valid_drivename($opt)) {
4019 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
4020 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
4026 my $scsihwid="scsihw
$controller";
4028 vm_deviceunplug($vmid, $conf, $scsihwid);
4033 sub qemu_add_pci_bridge {
4034 my ($storecfg, $conf, $vmid, $device) = @_;
4040 print_pci_addr($device, $bridges);
4042 while (my ($k, $v) = each %$bridges) {
4045 return 1 if !defined($bridgeid) || $bridgeid < 1;
4047 my $bridge = "pci
.$bridgeid";
4048 my $devices_list = vm_devices_list($vmid);
4050 if (!defined($devices_list->{$bridge})) {
4051 vm_deviceplug($storecfg, $conf, $vmid, $bridge);
4057 sub qemu_set_link_status {
4058 my ($vmid, $device, $up) = @_;
4060 vm_mon_cmd($vmid, "set_link
", name => $device,
4061 up => $up ? JSON::true : JSON::false);
4064 sub qemu_netdevadd {
4065 my ($vmid, $conf, $device, $deviceid) = @_;
4067 my $netdev = print_netdev_full($vmid, $conf, $device, $deviceid, 1);
4068 my %options = split(/[=,]/, $netdev);
4070 vm_mon_cmd($vmid, "netdev_add
", %options);
4074 sub qemu_netdevdel {
4075 my ($vmid, $deviceid) = @_;
4077 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
4080 sub qemu_usb_hotplug {
4081 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
4085 # remove the old one first
4086 vm_deviceunplug($vmid, $conf, $deviceid);
4088 # check if xhci controller is necessary and available
4089 if ($device->{usb3}) {
4091 my $devicelist = vm_devices_list($vmid);
4093 if (!$devicelist->{xhci}) {
4094 my $pciaddr = print_pci_addr("xhci
");
4095 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4098 my $d = parse_usb_device($device->{host});
4099 $d->{usb3} = $device->{usb3};
4102 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d);
4105 sub qemu_cpu_hotplug {
4106 my ($vmid, $conf, $vcpus) = @_;
4108 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4111 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4112 $sockets = $conf->{sockets} if $conf->{sockets};
4113 my $cores = $conf->{cores} || 1;
4114 my $maxcpus = $sockets * $cores;
4116 $vcpus = $maxcpus if !$vcpus;
4118 die "you can
't add more vcpus than maxcpus\n"
4119 if $vcpus > $maxcpus;
4121 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4123 if ($vcpus < $currentvcpus) {
4125 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4127 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4128 qemu_devicedel($vmid, "cpu$i");
4130 my $currentrunningvcpus = undef;
4132 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4133 last if scalar(@{$currentrunningvcpus}) == $i-1;
4134 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4138 #update conf after each succesfull cpu unplug
4139 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4140 PVE::QemuConfig->write_config($vmid, $conf);
4143 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4149 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4150 die "vcpus in running vm does not match its configuration\n"
4151 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4153 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4155 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4156 my $cpustr = print_cpu_device($conf, $i);
4157 qemu_deviceadd($vmid, $cpustr);
4160 my $currentrunningvcpus = undef;
4162 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4163 last if scalar(@{$currentrunningvcpus}) == $i;
4164 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4168 #update conf after each succesfull cpu hotplug
4169 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4170 PVE::QemuConfig->write_config($vmid, $conf);
4174 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4175 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4180 sub qemu_block_set_io_throttle {
4181 my ($vmid, $deviceid,
4182 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4183 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4184 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4185 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4187 return if !check_running($vmid) ;
4189 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4191 bps_rd => int($bps_rd),
4192 bps_wr => int($bps_wr),
4194 iops_rd => int($iops_rd),
4195 iops_wr => int($iops_wr),
4196 bps_max => int($bps_max),
4197 bps_rd_max => int($bps_rd_max),
4198 bps_wr_max => int($bps_wr_max),
4199 iops_max => int($iops_max),
4200 iops_rd_max => int($iops_rd_max),
4201 iops_wr_max => int($iops_wr_max),
4202 bps_max_length => int($bps_max_length),
4203 bps_rd_max_length => int($bps_rd_max_length),
4204 bps_wr_max_length => int($bps_wr_max_length),
4205 iops_max_length => int($iops_max_length),
4206 iops_rd_max_length => int($iops_rd_max_length),
4207 iops_wr_max_length => int($iops_wr_max_length),
4212 # old code, only used to shutdown old VM after update
4214 my ($fh, $timeout) = @_;
4216 my $sel = new IO::Select;
4223 while (scalar (@ready = $sel->can_read($timeout))) {
4225 if ($count = $fh->sysread($buf, 8192)) {
4226 if ($buf =~ /^(.*)\(qemu\) $/s) {
4233 if (!defined($count)) {
4240 die "monitor read timeout\n" if !scalar(@ready);
4245 sub qemu_block_resize {
4246 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4248 my $running = check_running($vmid);
4250 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4252 return if !$running;
4254 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4258 sub qemu_volume_snapshot {
4259 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4261 my $running = check_running($vmid);
4263 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4264 vm_mon_cmd($vmid, "snapshot-drive", device => $deviceid, name => $snap);
4266 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4270 sub qemu_volume_snapshot_delete {
4271 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4273 my $running = check_running($vmid);
4278 my $conf = PVE::QemuConfig->load_config($vmid);
4279 foreach_drive($conf, sub {
4280 my ($ds, $drive) = @_;
4281 $running = 1 if $drive->{file} eq $volid;
4285 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4286 vm_mon_cmd($vmid, "delete-drive-snapshot", device => $deviceid, name => $snap);
4288 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4292 sub set_migration_caps {
4298 "auto-converge" => 1,
4300 "x-rdma-pin-all" => 0,
4305 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4307 for my $supported_capability (@$supported_capabilities) {
4309 capability => $supported_capability->{capability},
4310 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4314 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4317 my $fast_plug_option = {
4325 'vmstatestorage
' => 1,
4328 # hotplug changes in [PENDING]
4329 # $selection hash can be used to only apply specified options, for
4330 # example: { cores => 1 } (only apply changed 'cores
')
4331 # $errors ref is used to return error messages
4332 sub vmconfig_hotplug_pending {
4333 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4335 my $defaults = load_defaults();
4337 # commit values which do not have any impact on running VM first
4338 # Note: those option cannot raise errors, we we do not care about
4339 # $selection and always apply them.
4341 my $add_error = sub {
4342 my ($opt, $msg) = @_;
4343 $errors->{$opt} = "hotplug problem - $msg";
4347 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4348 if ($fast_plug_option->{$opt}) {
4349 $conf->{$opt} = $conf->{pending}->{$opt};
4350 delete $conf->{pending}->{$opt};
4356 PVE::QemuConfig->write_config($vmid, $conf);
4357 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4360 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4362 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4363 while (my ($opt, $force) = each %$pending_delete_hash) {
4364 next if $selection && !$selection->{$opt};
4366 if ($opt eq 'hotplug
') {
4367 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4368 } elsif ($opt eq 'tablet
') {
4369 die "skip\n" if !$hotplug_features->{usb};
4370 if ($defaults->{tablet}) {
4371 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4373 vm_deviceunplug($vmid, $conf, $opt);
4375 } elsif ($opt =~ m/^usb\d+/) {
4377 # since we cannot reliably hot unplug usb devices
4378 # we are disabling it
4379 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4380 vm_deviceunplug($vmid, $conf, $opt);
4381 } elsif ($opt eq 'vcpus
') {
4382 die "skip\n" if !$hotplug_features->{cpu};
4383 qemu_cpu_hotplug($vmid, $conf, undef);
4384 } elsif ($opt eq 'balloon
') {
4385 # enable balloon device is not hotpluggable
4386 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4387 # here we reset the ballooning value to memory
4388 my $balloon = $conf->{memory} || $defaults->{memory};
4389 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4390 } elsif ($fast_plug_option->{$opt}) {
4392 } elsif ($opt =~ m/^net(\d+)$/) {
4393 die "skip\n" if !$hotplug_features->{network};
4394 vm_deviceunplug($vmid, $conf, $opt);
4395 } elsif (is_valid_drivename($opt)) {
4396 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4397 vm_deviceunplug($vmid, $conf, $opt);
4398 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4399 } elsif ($opt =~ m/^memory$/) {
4400 die "skip\n" if !$hotplug_features->{memory};
4401 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4402 } elsif ($opt eq 'cpuunits
') {
4403 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4404 } elsif ($opt eq 'cpulimit
') {
4405 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4411 &$add_error($opt, $err) if $err ne "skip\n";
4413 # save new config if hotplug was successful
4414 delete $conf->{$opt};
4415 vmconfig_undelete_pending_option($conf, $opt);
4416 PVE::QemuConfig->write_config($vmid, $conf);
4417 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4421 my $apply_pending_cloudinit;
4422 $apply_pending_cloudinit = sub {
4423 my ($key, $value) = @_;
4424 $apply_pending_cloudinit = sub {}; # once is enough
4426 my @cloudinit_opts = keys %$confdesc_cloudinit;
4427 foreach my $opt (keys %{$conf->{pending}}) {
4428 next if !grep { $_ eq $opt } @cloudinit_opts;
4429 $conf->{$opt} = delete $conf->{pending}->{$opt};
4432 my $new_conf = { %$conf };
4433 $new_conf->{$key} = $value;
4434 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4437 foreach my $opt (keys %{$conf->{pending}}) {
4438 next if $selection && !$selection->{$opt};
4439 my $value = $conf->{pending}->{$opt};
4441 if ($opt eq 'hotplug
') {
4442 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4443 } elsif ($opt eq 'tablet
') {
4444 die "skip\n" if !$hotplug_features->{usb};
4446 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4447 } elsif ($value == 0) {
4448 vm_deviceunplug($vmid, $conf, $opt);
4450 } elsif ($opt =~ m/^usb\d+$/) {
4452 # since we cannot reliably hot unplug usb devices
4453 # we are disabling it
4454 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4455 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4456 die "skip\n" if !$d;
4457 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d);
4458 } elsif ($opt eq 'vcpus
') {
4459 die "skip\n" if !$hotplug_features->{cpu};
4460 qemu_cpu_hotplug($vmid, $conf, $value);
4461 } elsif ($opt eq 'balloon
') {
4462 # enable/disable balloning device is not hotpluggable
4463 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4464 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4465 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4467 # allow manual ballooning if shares is set to zero
4468 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4469 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4470 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4472 } elsif ($opt =~ m/^net(\d+)$/) {
4473 # some changes can be done without hotplug
4474 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4475 $vmid, $opt, $value);
4476 } elsif (is_valid_drivename($opt)) {
4477 # some changes can be done without hotplug
4478 my $drive = parse_drive($opt, $value);
4479 if (drive_is_cloudinit($drive)) {
4480 &$apply_pending_cloudinit($opt, $value);
4482 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4483 $vmid, $opt, $value, 1);
4484 } elsif ($opt =~ m/^memory$/) { #dimms
4485 die "skip\n" if !$hotplug_features->{memory};
4486 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4487 } elsif ($opt eq 'cpuunits
') {
4488 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4489 } elsif ($opt eq 'cpulimit
') {
4490 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4491 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4493 die "skip\n"; # skip non-hot-pluggable options
4497 &$add_error($opt, $err) if $err ne "skip\n";
4499 # save new config if hotplug was successful
4500 $conf->{$opt} = $value;
4501 delete $conf->{pending}->{$opt};
4502 PVE::QemuConfig->write_config($vmid, $conf);
4503 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4508 sub try_deallocate_drive {
4509 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4511 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4512 my $volid = $drive->{file};
4513 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4514 my $sid = PVE::Storage::parse_volume_id($volid);
4515 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4517 # check if the disk is really unused
4518 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4519 if is_volume_in_use($storecfg, $conf, $key, $volid);
4520 PVE::Storage::vdisk_free($storecfg, $volid);
4523 # If vm is not owner of this disk remove from config
4531 sub vmconfig_delete_or_detach_drive {
4532 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4534 my $drive = parse_drive($opt, $conf->{$opt});
4536 my $rpcenv = PVE::RPCEnvironment::get();
4537 my $authuser = $rpcenv->get_user();
4540 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4541 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4543 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4547 sub vmconfig_apply_pending {
4548 my ($vmid, $conf, $storecfg) = @_;
4552 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4553 while (my ($opt, $force) = each %$pending_delete_hash) {
4554 die "internal error" if $opt =~ m/^unused/;
4555 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4556 if (!defined($conf->{$opt})) {
4557 vmconfig_undelete_pending_option($conf, $opt);
4558 PVE::QemuConfig->write_config($vmid, $conf);
4559 } elsif (is_valid_drivename($opt)) {
4560 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4561 vmconfig_undelete_pending_option($conf, $opt);
4562 delete $conf->{$opt};
4563 PVE::QemuConfig->write_config($vmid, $conf);
4565 vmconfig_undelete_pending_option($conf, $opt);
4566 delete $conf->{$opt};
4567 PVE::QemuConfig->write_config($vmid, $conf);
4571 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4573 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4574 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4576 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4577 # skip if nothing changed
4578 } elsif (is_valid_drivename($opt)) {
4579 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4580 if defined($conf->{$opt});
4581 $conf->{$opt} = $conf->{pending}->{$opt};
4583 $conf->{$opt} = $conf->{pending}->{$opt};
4586 delete $conf->{pending}->{$opt};
4587 PVE::QemuConfig->write_config($vmid, $conf);
4591 my $safe_num_ne = sub {
4594 return 0 if !defined($a) && !defined($b);
4595 return 1 if !defined($a);
4596 return 1 if !defined($b);
4601 my $safe_string_ne = sub {
4604 return 0 if !defined($a) && !defined($b);
4605 return 1 if !defined($a);
4606 return 1 if !defined($b);
4611 sub vmconfig_update_net {
4612 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value) = @_;
4614 my $newnet = parse_net($value);
4616 if ($conf->{$opt}) {
4617 my $oldnet = parse_net($conf->{$opt});
4619 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4620 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4621 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4622 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4624 # for non online change, we try to hot-unplug
4625 die "skip\n" if !$hotplug;
4626 vm_deviceunplug($vmid, $conf, $opt);
4629 die "internal error" if $opt !~ m/net(\d+)/;
4630 my $iface = "tap${vmid}i$1";
4632 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4633 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4634 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4635 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4636 PVE::Network::tap_unplug($iface);
4637 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4638 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4639 # Rate can be applied on its own but any change above needs to
4640 # include the rate in tap_plug since OVS resets everything.
4641 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4644 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4645 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4653 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet);
4659 sub vmconfig_update_disk {
4660 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force) = @_;
4662 # fixme: do we need force?
4664 my $drive = parse_drive($opt, $value);
4666 if ($conf->{$opt}) {
4668 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4670 my $media = $drive->{media} || 'disk
';
4671 my $oldmedia = $old_drive->{media} || 'disk
';
4672 die "unable to change media type\n" if $media ne $oldmedia;
4674 if (!drive_is_cdrom($old_drive)) {
4676 if ($drive->{file} ne $old_drive->{file}) {
4678 die "skip\n" if !$hotplug;
4680 # unplug and register as unused
4681 vm_deviceunplug($vmid, $conf, $opt);
4682 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4685 # update existing disk
4687 # skip non hotpluggable value
4688 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4689 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4690 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4691 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
4696 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4697 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4698 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4699 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4700 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4701 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4702 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4703 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4704 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4705 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4706 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4707 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4708 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4709 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4710 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4711 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4712 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4713 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4715 qemu_block_set_io_throttle($vmid,"drive-$opt",
4716 ($drive->{mbps} || 0)*1024*1024,
4717 ($drive->{mbps_rd} || 0)*1024*1024,
4718 ($drive->{mbps_wr} || 0)*1024*1024,
4719 $drive->{iops} || 0,
4720 $drive->{iops_rd} || 0,
4721 $drive->{iops_wr} || 0,
4722 ($drive->{mbps_max} || 0)*1024*1024,
4723 ($drive->{mbps_rd_max} || 0)*1024*1024,
4724 ($drive->{mbps_wr_max} || 0)*1024*1024,
4725 $drive->{iops_max} || 0,
4726 $drive->{iops_rd_max} || 0,
4727 $drive->{iops_wr_max} || 0,
4728 $drive->{bps_max_length} || 1,
4729 $drive->{bps_rd_max_length} || 1,
4730 $drive->{bps_wr_max_length} || 1,
4731 $drive->{iops_max_length} || 1,
4732 $drive->{iops_rd_max_length} || 1,
4733 $drive->{iops_wr_max_length} || 1);
4742 if ($drive->{file} eq 'none
') {
4743 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
4744 if (drive_is_cloudinit($old_drive)) {
4745 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
4748 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4749 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
4750 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
4758 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4760 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
4761 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive);
4765 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
4766 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
4768 PVE::QemuConfig->lock_config($vmid, sub {
4769 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
4771 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
4773 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4775 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
4777 if (!$statefile && scalar(keys %{$conf->{pending}})) {
4778 vmconfig_apply_pending($vmid, $conf, $storecfg);
4779 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4782 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
4784 my $defaults = load_defaults();
4786 # set environment variable useful inside network script
4787 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
4789 my $local_volumes = {};
4791 if ($targetstorage) {
4792 foreach_drive($conf, sub {
4793 my ($ds, $drive) = @_;
4795 return if drive_is_cdrom($drive);
4797 my $volid = $drive->{file};
4801 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
4803 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4804 return if $scfg->{shared};
4805 $local_volumes->{$ds} = [$volid, $storeid, $volname];
4810 foreach my $opt (sort keys %$local_volumes) {
4812 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
4813 my $drive = parse_drive($opt, $conf->{$opt});
4815 #if remote storage is specified, use default format
4816 if ($targetstorage && $targetstorage ne "1") {
4817 $storeid = $targetstorage;
4818 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
4819 $format = $defFormat;
4821 #else we use same format than original
4822 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4823 $format = qemu_img_format($scfg, $volid);
4826 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
4827 my $newdrive = $drive;
4828 $newdrive->{format} = $format;
4829 $newdrive->{file} = $newvolid;
4830 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
4831 $local_volumes->{$opt} = $drivestr;
4832 #pass drive to conf for command line
4833 $conf->{$opt} = $drivestr;
4837 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
4839 my $migrate_port = 0;
4842 if ($statefile eq 'tcp
') {
4843 my $localip = "localhost";
4844 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
4845 my $nodename = PVE::INotify::nodename();
4847 if (!defined($migration_type)) {
4848 if (defined($datacenterconf->{migration}->{type})) {
4849 $migration_type = $datacenterconf->{migration}->{type};
4851 $migration_type = 'secure
';
4855 if ($migration_type eq 'insecure
') {
4856 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
4857 if ($migrate_network_addr) {
4858 $localip = $migrate_network_addr;
4860 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
4863 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4866 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4867 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4868 $migrate_uri = "tcp:${localip}:${migrate_port}";
4869 push @$cmd, '-incoming
', $migrate_uri;
4872 } elsif ($statefile eq 'unix
') {
4873 # should be default for secure migrations as a ssh TCP forward
4874 # tunnel is not deterministic reliable ready and fails regurarly
4875 # to set up in time, so use UNIX socket forwards
4876 my $socket_addr = "/run/qemu-server/$vmid.migrate";
4877 unlink $socket_addr;
4879 $migrate_uri = "unix:$socket_addr";
4881 push @$cmd, '-incoming
', $migrate_uri;
4885 push @$cmd, '-loadstate
', $statefile;
4892 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
4893 my $d = parse_hostpci($conf->{"hostpci$i"});
4895 my $pcidevices = $d->{pciid};
4896 foreach my $pcidevice (@$pcidevices) {
4897 my $pciid = $pcidevice->{id}.".".$pcidevice->{function};
4899 my $info = pci_device_info("0000:$pciid");
4900 die "IOMMU not present\n" if !check_iommu_support();
4901 die "no pci device info for device '$pciid'\n" if !$info;
4902 die "can't unbind
/bind pci group to vfio
'$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
4903 die "can
't reset pci device '$pciid'\n" if $info->{has_fl_reset} and !pci_dev_reset($info);
4907 PVE::Storage::activate_volumes($storecfg, $vollist);
4909 if (!check_running($vmid, 1)) {
4911 run_command(['/bin/systemctl
', 'stop
', "$vmid.scope"],
4912 outfunc => sub {}, errfunc => sub {});
4916 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
4917 : $defaults->{cpuunits};
4919 my $start_timeout = $conf->{hugepages} ? 300 : 30;
4920 my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
4923 Slice => 'qemu
.slice
',
4925 CPUShares => $cpuunits
4928 if (my $cpulimit = $conf->{cpulimit}) {
4929 $properties{CPUQuota} = int($cpulimit * 100);
4931 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
4933 my $run_qemu = sub {
4934 PVE::Tools::run_fork sub {
4935 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4936 run_command($cmd, %run_params);
4940 if ($conf->{hugepages}) {
4943 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
4944 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
4946 PVE::QemuServer::Memory::hugepages_mount();
4947 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
4949 eval { $run_qemu->() };
4951 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
4955 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
4957 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
4960 eval { $run_qemu->() };
4964 # deactivate volumes if start fails
4965 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
4966 die "start failed: $err";
4969 print "migration listens on $migrate_uri\n" if $migrate_uri;
4971 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
4972 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
4976 #start nbd server for storage migration
4977 if ($targetstorage) {
4978 my $nodename = PVE::INotify::nodename();
4979 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
4980 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
4981 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4982 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4984 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${migrate_port}" } } );
4986 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4988 foreach my $opt (sort keys %$local_volumes) {
4989 my $volid = $local_volumes->{$opt};
4990 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
4991 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
4992 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
4996 if ($migratedfrom) {
4998 set_migration_caps($vmid);
5003 print "spice listens on port $spice_port\n";
5004 if ($spice_ticket) {
5005 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
5006 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
5011 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5012 if !$statefile && $conf->{balloon};
5014 foreach my $opt (keys %$conf) {
5015 next if $opt !~ m/^net\d+$/;
5016 my $nicconf = parse_net($conf->{$opt});
5017 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
5021 vm_mon_cmd_nocheck($vmid, 'qom-set
',
5022 path => "machine/peripheral/balloon0",
5023 property => "guest-stats-polling-interval",
5024 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
5030 my ($vmid, $execute, %params) = @_;
5032 my $cmd = { execute => $execute, arguments => \%params };
5033 vm_qmp_command($vmid, $cmd);
5036 sub vm_mon_cmd_nocheck {
5037 my ($vmid, $execute, %params) = @_;
5039 my $cmd = { execute => $execute, arguments => \%params };
5040 vm_qmp_command($vmid, $cmd, 1);
5043 sub vm_qmp_command {
5044 my ($vmid, $cmd, $nocheck) = @_;
5049 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
5050 $timeout = $cmd->{arguments}->{timeout};
5051 delete $cmd->{arguments}->{timeout};
5055 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
5056 my $sname = qmp_socket($vmid);
5057 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
5058 my $qmpclient = PVE::QMPClient->new();
5060 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
5062 die "unable to open monitor socket\n";
5066 syslog("err", "VM $vmid qmp command failed - $err");
5073 sub vm_human_monitor_command {
5074 my ($vmid, $cmdline) = @_;
5079 execute => 'human-monitor-command
',
5080 arguments => { 'command-line
' => $cmdline},
5083 return vm_qmp_command($vmid, $cmd);
5086 sub vm_commandline {
5087 my ($storecfg, $vmid) = @_;
5089 my $conf = PVE::QemuConfig->load_config($vmid);
5091 my $defaults = load_defaults();
5093 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
5095 return PVE::Tools::cmd2string($cmd);
5099 my ($vmid, $skiplock) = @_;
5101 PVE::QemuConfig->lock_config($vmid, sub {
5103 my $conf = PVE::QemuConfig->load_config($vmid);
5105 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5107 vm_mon_cmd($vmid, "system_reset");
5111 sub get_vm_volumes {
5115 foreach_volid($conf, sub {
5116 my ($volid, $attr) = @_;
5118 return if $volid =~ m|^/|;
5120 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5123 push @$vollist, $volid;
5129 sub vm_stop_cleanup {
5130 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5135 my $vollist = get_vm_volumes($conf);
5136 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5139 foreach my $ext (qw(mon qmp pid vnc qga)) {
5140 unlink "/var/run/qemu-server/${vmid}.$ext";
5143 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5145 warn $@ if $@; # avoid errors - just warn
5148 # Note: use $nockeck to skip tests if VM configuration file exists.
5149 # We need that when migration VMs to other nodes (files already moved)
5150 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5152 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5154 $force = 1 if !defined($force) && !$shutdown;
5157 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5158 kill 15, $pid if $pid;
5159 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5160 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5164 PVE
::QemuConfig-
>lock_config($vmid, sub {
5166 my $pid = check_running
($vmid, $nocheck);
5171 $conf = PVE
::QemuConfig-
>load_config($vmid);
5172 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5173 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5174 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5175 $timeout = $opts->{down
} if $opts->{down
};
5179 $timeout = 60 if !defined($timeout);
5183 if (defined($conf) && parse_guest_agent
($conf)->{enabled
}) {
5184 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
5186 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
5189 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
5196 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5201 if ($count >= $timeout) {
5203 warn "VM still running - terminating now with SIGTERM\n";
5206 die "VM quit/powerdown failed - got timeout\n";
5209 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5214 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5217 die "VM quit/powerdown failed\n";
5225 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5230 if ($count >= $timeout) {
5231 warn "VM still running - terminating now with SIGKILL\n";
5236 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5241 my ($vmid, $skiplock) = @_;
5243 PVE
::QemuConfig-
>lock_config($vmid, sub {
5245 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5247 PVE
::QemuConfig-
>check_lock($conf)
5248 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5250 vm_mon_cmd
($vmid, "stop");
5255 my ($vmid, $skiplock, $nocheck) = @_;
5257 PVE
::QemuConfig-
>lock_config($vmid, sub {
5259 my $res = vm_mon_cmd
($vmid, 'query-status');
5260 my $resume_cmd = 'cont';
5262 if ($res->{status
} && $res->{status
} eq 'suspended') {
5263 $resume_cmd = 'system_wakeup';
5268 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5270 PVE
::QemuConfig-
>check_lock($conf)
5271 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5273 vm_mon_cmd
($vmid, $resume_cmd);
5276 vm_mon_cmd_nocheck
($vmid, $resume_cmd);
5282 my ($vmid, $skiplock, $key) = @_;
5284 PVE
::QemuConfig-
>lock_config($vmid, sub {
5286 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5288 # there is no qmp command, so we use the human monitor command
5289 vm_human_monitor_command
($vmid, "sendkey $key");
5294 my ($storecfg, $vmid, $skiplock) = @_;
5296 PVE
::QemuConfig-
>lock_config($vmid, sub {
5298 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5300 if (!check_running
($vmid)) {
5301 destroy_vm
($storecfg, $vmid, undef, $skiplock);
5303 die "VM $vmid is running - destroy failed\n";
5311 my ($filename, $buf) = @_;
5313 my $fh = IO
::File-
>new($filename, "w");
5314 return undef if !$fh;
5316 my $res = print $fh $buf;
5323 sub pci_device_info
{
5328 return undef if $name !~ m/^([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\.([a-f0-9])$/;
5329 my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4);
5331 my $irq = file_read_firstline
("$pcisysfs/devices/$name/irq");
5332 return undef if !defined($irq) || $irq !~ m/^\d+$/;
5334 my $vendor = file_read_firstline
("$pcisysfs/devices/$name/vendor");
5335 return undef if !defined($vendor) || $vendor !~ s/^0x//;
5337 my $product = file_read_firstline
("$pcisysfs/devices/$name/device");
5338 return undef if !defined($product) || $product !~ s/^0x//;
5343 product
=> $product,
5349 has_fl_reset
=> -f
"$pcisysfs/devices/$name/reset" || 0,
5358 my $name = $dev->{name
};
5360 my $fn = "$pcisysfs/devices/$name/reset";
5362 return file_write
($fn, "1");
5365 sub pci_dev_bind_to_vfio
{
5368 my $name = $dev->{name
};
5370 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5372 if (!-d
$vfio_basedir) {
5373 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5375 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5377 my $testdir = "$vfio_basedir/$name";
5378 return 1 if -d
$testdir;
5380 my $data = "$dev->{vendor} $dev->{product}";
5381 return undef if !file_write
("$vfio_basedir/new_id", $data);
5383 my $fn = "$pcisysfs/devices/$name/driver/unbind";
5384 if (!file_write
($fn, $name)) {
5385 return undef if -f
$fn;
5388 $fn = "$vfio_basedir/bind";
5389 if (! -d
$testdir) {
5390 return undef if !file_write
($fn, $name);
5396 sub pci_dev_group_bind_to_vfio
{
5399 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5401 if (!-d
$vfio_basedir) {
5402 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5404 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5406 # get IOMMU group devices
5407 opendir(my $D, "$pcisysfs/devices/0000:$pciid/iommu_group/devices/") || die "Cannot open iommu_group: $!\n";
5408 my @devs = grep /^0000:/, readdir($D);
5411 foreach my $pciid (@devs) {
5412 $pciid =~ m/^([:\.\da-f]+)$/ or die "PCI ID $pciid not valid!\n";
5414 # pci bridges, switches or root ports are not supported
5415 # they have a pci_bus subdirectory so skip them
5416 next if (-e
"$pcisysfs/devices/$pciid/pci_bus");
5418 my $info = pci_device_info
($1);
5419 pci_dev_bind_to_vfio
($info) || die "Cannot bind $pciid to vfio\n";
5425 # vzdump restore implementaion
5427 sub tar_archive_read_firstfile
{
5428 my $archive = shift;
5430 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5432 # try to detect archive type first
5433 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5434 die "unable to open file '$archive'\n";
5435 my $firstfile = <$fh>;
5439 die "ERROR: archive contaions no data\n" if !$firstfile;
5445 sub tar_restore_cleanup
{
5446 my ($storecfg, $statfile) = @_;
5448 print STDERR
"starting cleanup\n";
5450 if (my $fd = IO
::File-
>new($statfile, "r")) {
5451 while (defined(my $line = <$fd>)) {
5452 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5455 if ($volid =~ m
|^/|) {
5456 unlink $volid || die 'unlink failed\n';
5458 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5460 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5462 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5464 print STDERR
"unable to parse line in statfile - $line";
5471 sub restore_archive
{
5472 my ($archive, $vmid, $user, $opts) = @_;
5474 my $format = $opts->{format
};
5477 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5478 $format = 'tar' if !$format;
5480 } elsif ($archive =~ m/\.tar$/) {
5481 $format = 'tar' if !$format;
5482 } elsif ($archive =~ m/.tar.lzo$/) {
5483 $format = 'tar' if !$format;
5485 } elsif ($archive =~ m/\.vma$/) {
5486 $format = 'vma' if !$format;
5487 } elsif ($archive =~ m/\.vma\.gz$/) {
5488 $format = 'vma' if !$format;
5490 } elsif ($archive =~ m/\.vma\.lzo$/) {
5491 $format = 'vma' if !$format;
5494 $format = 'vma' if !$format; # default
5497 # try to detect archive format
5498 if ($format eq 'tar') {
5499 return restore_tar_archive
($archive, $vmid, $user, $opts);
5501 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5505 sub restore_update_config_line
{
5506 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5508 return if $line =~ m/^\#qmdump\#/;
5509 return if $line =~ m/^\#vzdump\#/;
5510 return if $line =~ m/^lock:/;
5511 return if $line =~ m/^unused\d+:/;
5512 return if $line =~ m/^parent:/;
5513 return if $line =~ m/^template:/; # restored VM is never a template
5515 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5516 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5517 # try to convert old 1.X settings
5518 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5519 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5520 my ($model, $macaddr) = split(/\=/, $devconfig);
5521 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5524 bridge
=> "vmbr$ind",
5525 macaddr
=> $macaddr,
5527 my $netstr = print_net
($net);
5529 print $outfd "net$cookie->{netcount}: $netstr\n";
5530 $cookie->{netcount
}++;
5532 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5533 my ($id, $netstr) = ($1, $2);
5534 my $net = parse_net
($netstr);
5535 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5536 $netstr = print_net
($net);
5537 print $outfd "$id: $netstr\n";
5538 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5541 my $di = parse_drive
($virtdev, $value);
5542 if (defined($di->{backup
}) && !$di->{backup
}) {
5543 print $outfd "#$line";
5544 } elsif ($map->{$virtdev}) {
5545 delete $di->{format
}; # format can change on restore
5546 $di->{file
} = $map->{$virtdev};
5547 $value = print_drive
($vmid, $di);
5548 print $outfd "$virtdev: $value\n";
5552 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5553 my ($uuid, $uuid_str);
5554 UUID
::generate
($uuid);
5555 UUID
::unparse
($uuid, $uuid_str);
5556 my $smbios1 = parse_smbios1
($2);
5557 $smbios1->{uuid
} = $uuid_str;
5558 print $outfd $1.print_smbios1
($smbios1)."\n";
5565 my ($cfg, $vmid) = @_;
5567 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5569 my $volid_hash = {};
5570 foreach my $storeid (keys %$info) {
5571 foreach my $item (@{$info->{$storeid}}) {
5572 next if !($item->{volid
} && $item->{size
});
5573 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5574 $volid_hash->{$item->{volid
}} = $item;
5581 sub is_volume_in_use
{
5582 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5584 my $path = PVE
::Storage
::path
($storecfg, $volid);
5586 my $scan_config = sub {
5587 my ($cref, $snapname) = @_;
5589 foreach my $key (keys %$cref) {
5590 my $value = $cref->{$key};
5591 if (is_valid_drivename
($key)) {
5592 next if $skip_drive && $key eq $skip_drive;
5593 my $drive = parse_drive
($key, $value);
5594 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5595 return 1 if $volid eq $drive->{file
};
5596 if ($drive->{file
} =~ m!^/!) {
5597 return 1 if $drive->{file
} eq $path;
5599 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5601 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5603 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5611 return 1 if &$scan_config($conf);
5615 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5616 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5622 sub update_disksize
{
5623 my ($vmid, $conf, $volid_hash) = @_;
5626 my $prefix = "VM $vmid:";
5628 # used and unused disks
5629 my $referenced = {};
5631 # Note: it is allowed to define multiple storages with same path (alias), so
5632 # we need to check both 'volid' and real 'path' (two different volid can point
5633 # to the same path).
5635 my $referencedpath = {};
5638 foreach my $opt (keys %$conf) {
5639 if (is_valid_drivename
($opt)) {
5640 my $drive = parse_drive
($opt, $conf->{$opt});
5641 my $volid = $drive->{file
};
5644 $referenced->{$volid} = 1;
5645 if ($volid_hash->{$volid} &&
5646 (my $path = $volid_hash->{$volid}->{path
})) {
5647 $referencedpath->{$path} = 1;
5650 next if drive_is_cdrom
($drive);
5651 next if !$volid_hash->{$volid};
5653 $drive->{size
} = $volid_hash->{$volid}->{size
};
5654 my $new = print_drive
($vmid, $drive);
5655 if ($new ne $conf->{$opt}) {
5657 $conf->{$opt} = $new;
5658 print "$prefix update disk '$opt' information.\n";
5663 # remove 'unusedX' entry if volume is used
5664 foreach my $opt (keys %$conf) {
5665 next if $opt !~ m/^unused\d+$/;
5666 my $volid = $conf->{$opt};
5667 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5668 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5669 print "$prefix remove entry '$opt', its volume '$volid' is in use.\n";
5671 delete $conf->{$opt};
5674 $referenced->{$volid} = 1;
5675 $referencedpath->{$path} = 1 if $path;
5678 foreach my $volid (sort keys %$volid_hash) {
5679 next if $volid =~ m/vm-$vmid-state-/;
5680 next if $referenced->{$volid};
5681 my $path = $volid_hash->{$volid}->{path
};
5682 next if !$path; # just to be sure
5683 next if $referencedpath->{$path};
5685 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5686 print "$prefix add unreferenced volume '$volid' as '$key' to config.\n";
5687 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
5694 my ($vmid, $nolock, $dryrun) = @_;
5696 my $cfg = PVE
::Storage
::config
();
5698 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
5699 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
5700 foreach my $stor (keys %{$cfg->{ids
}}) {
5701 delete($cfg->{ids
}->{$stor}) if ! $cfg->{ids
}->{$stor}->{content
}->{images
};
5704 print "rescan volumes...\n";
5705 my $volid_hash = scan_volids
($cfg, $vmid);
5707 my $updatefn = sub {
5710 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5712 PVE
::QemuConfig-
>check_lock($conf);
5715 foreach my $volid (keys %$volid_hash) {
5716 my $info = $volid_hash->{$volid};
5717 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5720 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5722 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
5725 if (defined($vmid)) {
5729 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5732 my $vmlist = config_list
();
5733 foreach my $vmid (keys %$vmlist) {
5737 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5743 sub restore_vma_archive
{
5744 my ($archive, $vmid, $user, $opts, $comp) = @_;
5746 my $readfrom = $archive;
5748 my $cfg = PVE
::Storage
::config
();
5750 my $bwlimit = $opts->{bwlimit
};
5752 my $dbg_cmdstring = '';
5753 my $add_pipe = sub {
5755 push @$commands, $cmd;
5756 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
5757 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
5762 if ($archive eq '-') {
5765 # If we use a backup from a PVE defined storage we also consider that
5766 # storage's rate limit:
5767 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
5768 if (defined($volid)) {
5769 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
5770 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
5772 print STDERR
"applying read rate limit: $readlimit\n";
5773 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
5774 $add_pipe->($cstream);
5781 if ($comp eq 'gzip') {
5782 $cmd = ['zcat', $readfrom];
5783 } elsif ($comp eq 'lzop') {
5784 $cmd = ['lzop', '-d', '-c', $readfrom];
5786 die "unknown compression method '$comp'\n";
5791 my $tmpdir = "/var/tmp/vzdumptmp$$";
5794 # disable interrupts (always do cleanups)
5798 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
5800 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
5801 POSIX
::mkfifo
($mapfifo, 0600);
5804 my $openfifo = sub {
5805 open($fifofh, '>', $mapfifo) || die $!;
5808 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
5815 my $rpcenv = PVE
::RPCEnvironment
::get
();
5817 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5818 my $tmpfn = "$conffile.$$.tmp";
5820 # Note: $oldconf is undef if VM does not exists
5821 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
5822 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
5826 my $print_devmap = sub {
5827 my $virtdev_hash = {};
5829 my $cfgfn = "$tmpdir/qemu-server.conf";
5831 # we can read the config - that is already extracted
5832 my $fh = IO
::File-
>new($cfgfn, "r") ||
5833 "unable to read qemu-server.conf - $!\n";
5835 my $fwcfgfn = "$tmpdir/qemu-server.fw";
5837 my $pve_firewall_dir = '/etc/pve/firewall';
5838 mkdir $pve_firewall_dir; # make sure the dir exists
5839 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
5842 while (defined(my $line = <$fh>)) {
5843 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
5844 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
5845 die "archive does not contain data for drive '$virtdev'\n"
5846 if !$devinfo->{$devname};
5847 if (defined($opts->{storage
})) {
5848 $storeid = $opts->{storage
} || 'local';
5849 } elsif (!$storeid) {
5852 $format = 'raw' if !$format;
5853 $devinfo->{$devname}->{devname
} = $devname;
5854 $devinfo->{$devname}->{virtdev
} = $virtdev;
5855 $devinfo->{$devname}->{format
} = $format;
5856 $devinfo->{$devname}->{storeid
} = $storeid;
5858 # check permission on storage
5859 my $pool = $opts->{pool
}; # todo: do we need that?
5860 if ($user ne 'root@pam') {
5861 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
5864 $storage_limits{$storeid} = $bwlimit;
5866 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
5870 foreach my $key (keys %storage_limits) {
5871 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$key], $bwlimit);
5873 print STDERR
"rate limit for storage $key: $limit KiB/s\n";
5874 $storage_limits{$key} = $limit * 1024;
5877 foreach my $devname (keys %$devinfo) {
5878 die "found no device mapping information for device '$devname'\n"
5879 if !$devinfo->{$devname}->{virtdev
};
5882 # create empty/temp config
5884 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
5885 foreach_drive
($oldconf, sub {
5886 my ($ds, $drive) = @_;
5888 return if drive_is_cdrom
($drive);
5890 my $volid = $drive->{file
};
5892 return if !$volid || $volid =~ m
|^/|;
5894 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
5895 return if !$path || !$owner || ($owner != $vmid);
5897 # Note: only delete disk we want to restore
5898 # other volumes will become unused
5899 if ($virtdev_hash->{$ds}) {
5900 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
5907 # delete vmstate files
5908 # since after the restore we have no snapshots anymore
5909 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
5910 my $snap = $oldconf->{snapshots
}->{$snapname};
5911 if ($snap->{vmstate
}) {
5912 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
5921 foreach my $virtdev (sort keys %$virtdev_hash) {
5922 my $d = $virtdev_hash->{$virtdev};
5923 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
5924 my $storeid = $d->{storeid
};
5925 my $scfg = PVE
::Storage
::storage_config
($cfg, $storeid);
5928 if (my $limit = $storage_limits{$storeid}) {
5929 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
5932 # test if requested format is supported
5933 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $storeid);
5934 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
5935 $d->{format
} = $defFormat if !$supported;
5937 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $storeid, $vmid,
5938 $d->{format
}, undef, $alloc_size);
5939 print STDERR
"new volume ID is '$volid'\n";
5940 $d->{volid
} = $volid;
5941 my $path = PVE
::Storage
::path
($cfg, $volid);
5943 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
5945 my $write_zeros = 1;
5946 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
5950 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
5952 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
5953 $map->{$virtdev} = $volid;
5956 $fh->seek(0, 0) || die "seek failed - $!\n";
5958 my $outfd = new IO
::File
($tmpfn, "w") ||
5959 die "unable to write config for VM $vmid\n";
5961 my $cookie = { netcount
=> 0 };
5962 while (defined(my $line = <$fh>)) {
5963 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
5976 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
5977 local $SIG{ALRM
} = sub { die "got timeout\n"; };
5979 $oldtimeout = alarm($timeout);
5986 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
5987 my ($dev_id, $size, $devname) = ($1, $2, $3);
5988 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
5989 } elsif ($line =~ m/^CTIME: /) {
5990 # we correctly received the vma config, so we can disable
5991 # the timeout now for disk allocation (set to 10 minutes, so
5992 # that we always timeout if something goes wrong)
5995 print $fifofh "done\n";
5996 my $tmp = $oldtimeout || 0;
5997 $oldtimeout = undef;
6003 print "restore vma archive: $dbg_cmdstring\n";
6004 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
6008 alarm($oldtimeout) if $oldtimeout;
6011 foreach my $devname (keys %$devinfo) {
6012 my $volid = $devinfo->{$devname}->{volid
};
6013 push @$vollist, $volid if $volid;
6016 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
6024 foreach my $devname (keys %$devinfo) {
6025 my $volid = $devinfo->{$devname}->{volid
};
6028 if ($volid =~ m
|^/|) {
6029 unlink $volid || die 'unlink failed\n';
6031 PVE
::Storage
::vdisk_free
($cfg, $volid);
6033 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6035 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6042 rename($tmpfn, $conffile) ||
6043 die "unable to commit configuration file '$conffile'\n";
6045 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6047 eval { rescan
($vmid, 1); };
6051 sub restore_tar_archive
{
6052 my ($archive, $vmid, $user, $opts) = @_;
6054 if ($archive ne '-') {
6055 my $firstfile = tar_archive_read_firstfile
($archive);
6056 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6057 if $firstfile ne 'qemu-server.conf';
6060 my $storecfg = PVE
::Storage
::config
();
6062 # destroy existing data - keep empty config
6063 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
6064 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
6066 my $tocmd = "/usr/lib/qemu-server/qmextract";
6068 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
6069 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
6070 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6071 $tocmd .= ' --info' if $opts->{info
};
6073 # tar option "xf" does not autodetect compression when read from STDIN,
6074 # so we pipe to zcat
6075 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6076 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6078 my $tmpdir = "/var/tmp/vzdumptmp$$";
6081 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6082 local $ENV{VZDUMP_VMID
} = $vmid;
6083 local $ENV{VZDUMP_USER
} = $user;
6085 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6086 my $tmpfn = "$conffile.$$.tmp";
6088 # disable interrupts (always do cleanups)
6092 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6100 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6102 if ($archive eq '-') {
6103 print "extracting archive from STDIN\n";
6104 run_command
($cmd, input
=> "<&STDIN");
6106 print "extracting archive '$archive'\n";
6110 return if $opts->{info
};
6114 my $statfile = "$tmpdir/qmrestore.stat";
6115 if (my $fd = IO
::File-
>new($statfile, "r")) {
6116 while (defined (my $line = <$fd>)) {
6117 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6118 $map->{$1} = $2 if $1;
6120 print STDERR
"unable to parse line in statfile - $line\n";
6126 my $confsrc = "$tmpdir/qemu-server.conf";
6128 my $srcfd = new IO
::File
($confsrc, "r") ||
6129 die "unable to open file '$confsrc'\n";
6131 my $outfd = new IO
::File
($tmpfn, "w") ||
6132 die "unable to write config for VM $vmid\n";
6134 my $cookie = { netcount
=> 0 };
6135 while (defined (my $line = <$srcfd>)) {
6136 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6148 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6155 rename $tmpfn, $conffile ||
6156 die "unable to commit configuration file '$conffile'\n";
6158 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6160 eval { rescan
($vmid, 1); };
6164 sub foreach_storage_used_by_vm
{
6165 my ($conf, $func) = @_;
6169 foreach_drive
($conf, sub {
6170 my ($ds, $drive) = @_;
6171 return if drive_is_cdrom
($drive);
6173 my $volid = $drive->{file
};
6175 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6176 $sidhash->{$sid} = $sid if $sid;
6179 foreach my $sid (sort keys %$sidhash) {
6184 sub do_snapshots_with_qemu
{
6185 my ($storecfg, $volid) = @_;
6187 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6189 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
6190 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
6194 if ($volid =~ m/\.(qcow2|qed)$/){
6201 sub qga_check_running
{
6202 my ($vmid, $nowarn) = @_;
6204 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6206 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
6212 sub template_create
{
6213 my ($vmid, $conf, $disk) = @_;
6215 my $storecfg = PVE
::Storage
::config
();
6217 foreach_drive
($conf, sub {
6218 my ($ds, $drive) = @_;
6220 return if drive_is_cdrom
($drive);
6221 return if $disk && $ds ne $disk;
6223 my $volid = $drive->{file
};
6224 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6226 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6227 $drive->{file
} = $voliddst;
6228 $conf->{$ds} = print_drive
($vmid, $drive);
6229 PVE
::QemuConfig-
>write_config($vmid, $conf);
6233 sub qemu_img_convert
{
6234 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6236 my $storecfg = PVE
::Storage
::config
();
6237 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6238 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6240 if ($src_storeid && $dst_storeid) {
6242 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6244 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6245 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6247 my $src_format = qemu_img_format
($src_scfg, $src_volname);
6248 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6250 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6251 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6254 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6255 push @$cmd, '-s', $snapname if($snapname && $src_format eq "qcow2");
6256 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
6257 push @$cmd, '-T', 'none' if $src_scfg->{type
} eq 'zfspool';
6258 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
6259 if ($is_zero_initialized) {
6260 push @$cmd, "zeroinit:$dst_path";
6262 push @$cmd, $dst_path;
6267 if($line =~ m/\((\S+)\/100\
%\)/){
6269 my $transferred = int($size * $percent / 100);
6270 my $remaining = $size - $transferred;
6272 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6277 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6279 die "copy failed: $err" if $err;
6283 sub qemu_img_format
{
6284 my ($scfg, $volname) = @_;
6286 if ($scfg->{path
} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
6293 sub qemu_drive_mirror
{
6294 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga) = @_;
6296 $jobs = {} if !$jobs;
6300 $jobs->{"drive-$drive"} = {};
6302 if ($dst_volid =~ /^nbd:/) {
6303 $qemu_target = $dst_volid;
6306 my $storecfg = PVE
::Storage
::config
();
6307 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6309 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6311 $format = qemu_img_format
($dst_scfg, $dst_volname);
6313 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6315 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6318 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6319 $opts->{format
} = $format if $format;
6321 print "drive mirror is starting for drive-$drive\n";
6323 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
6326 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6327 die "mirroring error: $err";
6330 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
6333 sub qemu_drive_mirror_monitor
{
6334 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
6337 my $err_complete = 0;
6340 die "storage migration timed out\n" if $err_complete > 300;
6342 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6344 my $running_mirror_jobs = {};
6345 foreach my $stat (@$stats) {
6346 next if $stat->{type
} ne 'mirror';
6347 $running_mirror_jobs->{$stat->{device
}} = $stat;
6350 my $readycounter = 0;
6352 foreach my $job (keys %$jobs) {
6354 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6355 print "$job : finished\n";
6356 delete $jobs->{$job};
6360 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6362 my $busy = $running_mirror_jobs->{$job}->{busy
};
6363 my $ready = $running_mirror_jobs->{$job}->{ready
};
6364 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6365 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6366 my $remaining = $total - $transferred;
6367 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6369 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6372 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6375 last if scalar(keys %$jobs) == 0;
6377 if ($readycounter == scalar(keys %$jobs)) {
6378 print "all mirroring jobs are ready \n";
6379 last if $skipcomplete; #do the complete later
6381 if ($vmiddst && $vmiddst != $vmid) {
6382 my $agent_running = $qga && qga_check_running
($vmid);
6383 if ($agent_running) {
6384 print "freeze filesystem\n";
6385 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6387 print "suspend vm\n";
6388 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6391 # if we clone a disk for a new target vm, we don't switch the disk
6392 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6394 if ($agent_running) {
6395 print "unfreeze filesystem\n";
6396 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6398 print "resume vm\n";
6399 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6405 foreach my $job (keys %$jobs) {
6406 # try to switch the disk if source and destination are on the same guest
6407 print "$job: Completing block job...\n";
6409 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6410 if ($@ =~ m/cannot be completed/) {
6411 print "$job: Block job cannot be completed, try again.\n";
6414 print "$job: Completed successfully.\n";
6415 $jobs->{$job}->{complete
} = 1;
6426 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6427 die "mirroring error: $err";
6432 sub qemu_blockjobs_cancel
{
6433 my ($vmid, $jobs) = @_;
6435 foreach my $job (keys %$jobs) {
6436 print "$job: Cancelling block job\n";
6437 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6438 $jobs->{$job}->{cancel
} = 1;
6442 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6444 my $running_jobs = {};
6445 foreach my $stat (@$stats) {
6446 $running_jobs->{$stat->{device
}} = $stat;
6449 foreach my $job (keys %$jobs) {
6451 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6452 print "$job: Done.\n";
6453 delete $jobs->{$job};
6457 last if scalar(keys %$jobs) == 0;
6464 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6465 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;
6470 print "create linked clone of drive $drivename ($drive->{file})\n";
6471 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6472 push @$newvollist, $newvolid;
6475 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6476 $storeid = $storage if $storage;
6478 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
6479 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6481 print "create full clone of drive $drivename ($drive->{file})\n";
6483 if (drive_is_cloudinit
($drive)) {
6484 $name = "vm-$newvmid-cloudinit";
6485 # cloudinit only supports raw and qcow2 atm:
6486 if ($dst_format eq 'qcow2') {
6488 } elsif ($dst_format ne 'raw') {
6489 die "clone: unhandled format for cloudinit image\n";
6492 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
6493 push @$newvollist, $newvolid;
6495 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6497 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6498 if (!$running || $snapname) {
6499 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6502 my $kvmver = get_running_qemu_version
($vmid);
6503 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
6504 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6505 if $drive->{iothread
};
6508 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga);
6512 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6515 $disk->{format
} = undef;
6516 $disk->{file
} = $newvolid;
6517 $disk->{size
} = $size;
6522 # this only works if VM is running
6523 sub get_current_qemu_machine
{
6526 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
6527 my $res = vm_qmp_command
($vmid, $cmd);
6529 my ($current, $default);
6530 foreach my $e (@$res) {
6531 $default = $e->{name
} if $e->{'is-default'};
6532 $current = $e->{name
} if $e->{'is-current'};
6535 # fallback to the default machine if current is not supported by qemu
6536 return $current || $default || 'pc';
6539 sub get_running_qemu_version
{
6541 my $cmd = { execute
=> 'query-version', arguments
=> {} };
6542 my $res = vm_qmp_command
($vmid, $cmd);
6543 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6546 sub qemu_machine_feature_enabled
{
6547 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6552 if ($machine && $machine =~ m/^(pc(-i440fx|-q35)?-(\d+)\.(\d+))/) {
6554 $current_major = $3;
6555 $current_minor = $4;
6557 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6559 $current_major = $1;
6560 $current_minor = $2;
6563 return 1 if $current_major >= $version_major && $current_minor >= $version_minor;
6568 sub qemu_machine_pxe
{
6569 my ($vmid, $conf, $machine) = @_;
6571 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6573 if ($conf->{machine
} && $conf->{machine
} =~ m/\.pxe$/) {
6580 sub qemu_use_old_bios_files
{
6581 my ($machine_type) = @_;
6583 return if !$machine_type;
6585 my $use_old_bios_files = undef;
6587 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6589 $use_old_bios_files = 1;
6591 my $kvmver = kvm_user_version
();
6592 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6593 # load new efi bios files on migration. So this hack is required to allow
6594 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6595 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6596 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6599 return ($use_old_bios_files, $machine_type);
6602 sub create_efidisk
{
6603 my ($storecfg, $storeid, $vmid, $fmt) = @_;
6605 die "EFI vars default image not found\n" if ! -f
$OVMF_VARS;
6607 my $vars_size = PVE
::Tools
::convert_size
(-s
$OVMF_VARS, 'b' => 'kb');
6608 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6609 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6611 my $path = PVE
::Storage
::path
($storecfg, $volid);
6613 run_command
(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $OVMF_VARS, $path]);
6615 die "Copying EFI vars image failed: $@" if $@;
6617 return ($volid, $vars_size);
6624 dir_glob_foreach
("$pcisysfs/devices", '[a-f0-9]{4}:([a-f0-9]{2}:[a-f0-9]{2})\.([0-9])', sub {
6625 my (undef, $id, $function) = @_;
6626 my $res = { id
=> $id, function
=> $function};
6627 push @{$devices->{$id}}, $res;
6630 # Entries should be sorted by functions.
6631 foreach my $id (keys %$devices) {
6632 my $dev = $devices->{$id};
6633 $devices->{$id} = [ sort { $a->{function
} <=> $b->{function
} } @$dev ];
6639 sub vm_iothreads_list
{
6642 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6645 foreach my $iothread (@$res) {
6646 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6653 my ($conf, $drive) = @_;
6657 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
6659 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6665 my $controller = int($drive->{index} / $maxdev);
6666 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6668 return ($maxdev, $controller, $controller_prefix);
6671 sub add_hyperv_enlightenments
{
6672 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough) = @_;
6674 return if $winversion < 6;
6675 return if $bios && $bios eq 'ovmf' && $winversion < 8;
6677 push @$cpuFlags , 'hv_vendor_id=proxmox' if $gpu_passthrough;
6679 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
6680 push @$cpuFlags , 'hv_spinlocks=0x1fff';
6681 push @$cpuFlags , 'hv_vapic';
6682 push @$cpuFlags , 'hv_time';
6684 push @$cpuFlags , 'hv_spinlocks=0xffff';
6687 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
6688 push @$cpuFlags , 'hv_reset';
6689 push @$cpuFlags , 'hv_vpindex';
6690 push @$cpuFlags , 'hv_runtime';
6693 if ($winversion >= 7) {
6694 push @$cpuFlags , 'hv_relaxed';
6698 sub windows_version
{
6701 return 0 if !$ostype;
6705 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6707 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6709 } elsif ($ostype =~ m/^win(\d+)$/) {
6716 sub resolve_dst_disk_format
{
6717 my ($storecfg, $storeid, $src_volname, $format) = @_;
6718 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6721 # if no target format is specified, use the source disk format as hint
6723 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6724 $format = qemu_img_format
($scfg, $src_volname);
6730 # test if requested format is supported - else use default
6731 my $supported = grep { $_ eq $format } @$validFormats;
6732 $format = $defFormat if !$supported;
6736 sub resolve_first_disk
{
6738 my @disks = PVE
::QemuServer
::valid_drive_names
();
6740 foreach my $ds (reverse @disks) {
6741 next if !$conf->{$ds};
6742 my $disk = PVE
::QemuServer
::parse_drive
($ds, $conf->{$ds});
6743 next if PVE
::QemuServer
::drive_is_cdrom
($disk);
6749 sub generate_smbios1_uuid
{
6750 my ($uuid, $uuid_str);
6751 UUID
::generate
($uuid);
6752 UUID
::unparse
($uuid, $uuid_str);
6753 return "uuid=$uuid_str";
6756 # bash completion helper
6758 sub complete_backup_archives
{
6759 my ($cmdname, $pname, $cvalue) = @_;
6761 my $cfg = PVE
::Storage
::config
();
6765 if ($cvalue =~ m/^([^:]+):/) {
6769 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
6772 foreach my $id (keys %$data) {
6773 foreach my $item (@{$data->{$id}}) {
6774 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
6775 push @$res, $item->{volid
} if defined($item->{volid
});
6782 my $complete_vmid_full = sub {
6785 my $idlist = vmstatus
();
6789 foreach my $id (keys %$idlist) {
6790 my $d = $idlist->{$id};
6791 if (defined($running)) {
6792 next if $d->{template
};
6793 next if $running && $d->{status
} ne 'running';
6794 next if !$running && $d->{status
} eq 'running';
6803 return &$complete_vmid_full();
6806 sub complete_vmid_stopped
{
6807 return &$complete_vmid_full(0);
6810 sub complete_vmid_running
{
6811 return &$complete_vmid_full(1);
6814 sub complete_storage
{
6816 my $cfg = PVE
::Storage
::config
();
6817 my $ids = $cfg->{ids
};
6820 foreach my $sid (keys %$ids) {
6821 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
6822 next if !$ids->{$sid}->{content
}->{images
};
6832 vm_mon_cmd
($vmid, 'nbd-server-stop');