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
;
39 use Time
::HiRes
qw(gettimeofday);
40 use File
::Copy
qw(copy);
43 my $EDK2_FW_BASE = '/usr/share/pve-edk2-firmware/';
46 "$EDK2_FW_BASE/OVMF_CODE.fd",
47 "$EDK2_FW_BASE/OVMF_VARS.fd"
50 "$EDK2_FW_BASE/AAVMF_CODE.fd",
51 "$EDK2_FW_BASE/AAVMF_VARS.fd"
55 my $qemu_snap_storage = {rbd
=> 1, sheepdog
=> 1};
57 my $cpuinfo = PVE
::ProcFSTools
::read_cpuinfo
();
59 my $QEMU_FORMAT_RE = qr/raw|cow|qcow|qcow2|qed|vmdk|cloop/;
61 # Note about locking: we use flock on the config file protect
62 # against concurent actions.
63 # Aditionaly, we have a 'lock' setting in the config file. This
64 # can be set to 'migrate', 'backup', 'snapshot' or 'rollback'. Most actions are not
65 # allowed when such lock is set. But you can ignore this kind of
66 # lock with the --skiplock flag.
68 cfs_register_file
('/qemu-server/',
72 PVE
::JSONSchema
::register_standard_option
('pve-qm-stateuri', {
73 description
=> "Some command save/restore state from this location.",
79 PVE
::JSONSchema
::register_standard_option
('pve-snapshot-name', {
80 description
=> "The name of the snapshot.",
81 type
=> 'string', format
=> 'pve-configid',
85 PVE
::JSONSchema
::register_standard_option
('pve-qm-image-format', {
87 enum
=> [qw(raw cow qcow qed qcow2 vmdk cloop)],
88 description
=> "The drive's backing file's data format.",
92 PVE
::JSONSchema
::register_standard_option
('pve-qemu-machine', {
93 description
=> "Specifies the Qemu machine type.",
95 pattern
=> '(pc|pc(-i440fx)?-\d+\.\d+(\.pxe)?|q35|pc-q35-\d+\.\d+(\.pxe)?|virt(?:-\d+\.\d+)?)',
100 #no warnings 'redefine';
103 my ($controller, $vmid, $option, $value) = @_;
105 my $path = "/sys/fs/cgroup/$controller/qemu.slice/$vmid.scope/$option";
106 PVE
::ProcFSTools
::write_proc_entry
($path, $value);
110 my $nodename = PVE
::INotify
::nodename
();
112 mkdir "/etc/pve/nodes/$nodename";
113 my $confdir = "/etc/pve/nodes/$nodename/qemu-server";
116 my $var_run_tmpdir = "/var/run/qemu-server";
117 mkdir $var_run_tmpdir;
119 my $lock_dir = "/var/lock/qemu-server";
122 my $cpu_vendor_list = {
124 486 => 'GenuineIntel',
125 pentium
=> 'GenuineIntel',
126 pentium2
=> 'GenuineIntel',
127 pentium3
=> 'GenuineIntel',
128 coreduo
=> 'GenuineIntel',
129 core2duo
=> 'GenuineIntel',
130 Conroe
=> 'GenuineIntel',
131 Penryn
=> 'GenuineIntel',
132 Nehalem
=> 'GenuineIntel',
133 'Nehalem-IBRS' => 'GenuineIntel',
134 Westmere
=> 'GenuineIntel',
135 'Westmere-IBRS' => 'GenuineIntel',
136 SandyBridge
=> 'GenuineIntel',
137 'SandyBridge-IBRS' => 'GenuineIntel',
138 IvyBridge
=> 'GenuineIntel',
139 'IvyBridge-IBRS' => 'GenuineIntel',
140 Haswell
=> 'GenuineIntel',
141 'Haswell-IBRS' => 'GenuineIntel',
142 'Haswell-noTSX' => 'GenuineIntel',
143 'Haswell-noTSX-IBRS' => 'GenuineIntel',
144 Broadwell
=> 'GenuineIntel',
145 'Broadwell-IBRS' => 'GenuineIntel',
146 'Broadwell-noTSX' => 'GenuineIntel',
147 'Broadwell-noTSX-IBRS' => 'GenuineIntel',
148 'Skylake-Client' => 'GenuineIntel',
149 'Skylake-Client-IBRS' => 'GenuineIntel',
150 'Skylake-Server' => 'GenuineIntel',
151 'Skylake-Server-IBRS' => 'GenuineIntel',
154 athlon
=> 'AuthenticAMD',
155 phenom
=> 'AuthenticAMD',
156 Opteron_G1
=> 'AuthenticAMD',
157 Opteron_G2
=> 'AuthenticAMD',
158 Opteron_G3
=> 'AuthenticAMD',
159 Opteron_G4
=> 'AuthenticAMD',
160 Opteron_G5
=> 'AuthenticAMD',
161 EPYC
=> 'AuthenticAMD',
162 'EPYC-IBPB' => 'AuthenticAMD',
164 # generic types, use vendor from host node
173 my $cpu_flag = qr/[+-](pcid|spec-ctrl|ibpb|ssbd|virt-ssbd|amd-ssbd|amd-no-ssb|pdpe1gb)/;
177 description
=> "Emulated CPU type.",
179 enum
=> [ sort { "\L$a" cmp "\L$b" } keys %$cpu_vendor_list ],
184 description
=> "Do not identify as a KVM virtual machine.",
190 description
=> "List of additional CPU flags separated by ';'."
191 . " Use '+FLAG' to enable, '-FLAG' to disable a flag."
192 . " Currently supported flags: 'pcid', 'spec-ctrl', 'ibpb', 'ssbd', 'virt-ssbd', 'amd-ssbd', 'amd-no-ssb', 'pdpe1gb'.",
193 format_description
=> '+FLAG[;-FLAG...]',
195 pattern
=> qr/$cpu_flag(;$cpu_flag)*/,
204 enum
=> [qw(i6300esb ib700)],
205 description
=> "Watchdog type to emulate.",
206 default => 'i6300esb',
211 enum
=> [qw(reset shutdown poweroff pause debug none)],
212 description
=> "The action to perform if after activation the guest fails to poll the watchdog in time.",
216 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', $watchdog_fmt);
220 description
=> "Enable/disable Qemu GuestAgent.",
225 fstrim_cloned_disks
=> {
226 description
=> "Run fstrim after cloning/moving a disk.",
235 description
=> "Select the VGA type.",
240 enum
=> [qw(cirrus qxl qxl2 qxl3 qxl4 none serial0 serial1 serial2 serial3 std virtio vmware)],
243 description
=> "Sets the VGA memory (in MiB). Has no effect with serial display.",
255 description
=> "Specifies whether a VM will be started during system bootup.",
261 description
=> "Automatic restart after crash (currently ignored).",
266 type
=> 'string', format
=> 'pve-hotplug-features',
267 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'.",
268 default => 'network,disk,usb',
273 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
279 description
=> "Lock/unlock the VM.",
280 enum
=> [qw(backup clone create migrate rollback snapshot snapshot-delete)],
285 description
=> "Limit of CPU usage.",
286 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.",
294 description
=> "CPU weight for a VM.",
295 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.",
303 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
310 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
316 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.",
324 description
=> "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.cfg' configuration file.".
325 "It should not be necessary to set it.",
326 enum
=> PVE
::Tools
::kvmkeymaplist
(),
331 type
=> 'string', format
=> 'dns-name',
332 description
=> "Set a name for the VM. Only used on the configuration web interface.",
337 description
=> "SCSI controller model",
338 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
344 description
=> "Description for the VM. Only used on the configuration web interface. This is saved as comment inside the configuration file.",
349 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 l24 l26 solaris)],
350 description
=> "Specify guest operating system.",
351 verbose_description
=> <<EODESC,
352 Specify guest operating system. This is used to enable special
353 optimization/features for specific operating systems:
356 other;; unspecified OS
357 wxp;; Microsoft Windows XP
358 w2k;; Microsoft Windows 2000
359 w2k3;; Microsoft Windows 2003
360 w2k8;; Microsoft Windows 2008
361 wvista;; Microsoft Windows Vista
362 win7;; Microsoft Windows 7
363 win8;; Microsoft Windows 8/2012/2012r2
364 win10;; Microsoft Windows 10/2016
365 l24;; Linux 2.4 Kernel
366 l26;; Linux 2.6/3.X Kernel
367 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
373 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
374 pattern
=> '[acdn]{1,4}',
379 type
=> 'string', format
=> 'pve-qm-bootdisk',
380 description
=> "Enable booting from specified disk.",
381 pattern
=> '(ide|sata|scsi|virtio)\d+',
386 description
=> "The number of CPUs. Please use option -sockets instead.",
393 description
=> "The number of CPU sockets.",
400 description
=> "The number of cores per socket.",
407 description
=> "Enable/disable NUMA.",
413 description
=> "Enable/disable hugepages memory.",
414 enum
=> [qw(any 2 1024)],
419 description
=> "Number of hotplugged vcpus.",
426 description
=> "Enable/disable ACPI.",
431 description
=> "Enable/disable Qemu GuestAgent and its properties.",
433 format
=> $agent_fmt,
438 description
=> "Enable/disable KVM hardware virtualization.",
444 description
=> "Enable/disable time drift fix.",
450 description
=> "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
455 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
459 type
=> 'string', format
=> $vga_fmt,
460 description
=> "Configure the VGA hardware.",
461 verbose_description
=> "Configure the VGA Hardware. If you want to use ".
462 "high resolution modes (>= 1280x1024x16) you may need to increase " .
463 "the vga memory option. Since QEMU 2.9 the default VGA display type " .
464 "is 'std' for all OS types besides some Windows versions (XP and " .
465 "older) which use 'cirrus'. The 'qxl' option enables the SPICE " .
466 "display server. For win* OS you can select how many independent " .
467 "displays you want, Linux guests can add displays them self.\n".
468 "You can also run without any graphic card, using a serial device as terminal.",
472 type
=> 'string', format
=> 'pve-qm-watchdog',
473 description
=> "Create a virtual hardware watchdog device.",
474 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled" .
475 " (by a guest action), the watchdog must be periodically polled " .
476 "by an agent inside the guest or else the watchdog will reset " .
477 "the guest (or execute the respective action specified)",
482 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
483 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'.",
484 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
487 startup
=> get_standard_option
('pve-startup-order'),
491 description
=> "Enable/disable Template.",
497 description
=> "Arbitrary arguments passed to kvm.",
498 verbose_description
=> <<EODESCR,
499 Arbitrary arguments passed to kvm, for example:
501 args: -no-reboot -no-hpet
503 NOTE: this option is for experts only.
510 description
=> "Enable/disable the USB tablet device.",
511 verbose_description
=> "Enable/disable the USB tablet device. This device is " .
512 "usually needed to allow absolute mouse positioning with VNC. " .
513 "Else the mouse runs out of sync with normal VNC clients. " .
514 "If you're running lots of console-only guests on one host, " .
515 "you may consider disabling this to save some context switches. " .
516 "This is turned off by default if you use spice (-vga=qxl).",
521 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
525 migrate_downtime
=> {
528 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
534 type
=> 'string', format
=> 'pve-qm-ide',
535 typetext
=> '<volume>',
536 description
=> "This is an alias for option -ide2",
540 description
=> "Emulated CPU type.",
544 parent
=> get_standard_option
('pve-snapshot-name', {
546 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
550 description
=> "Timestamp for snapshots.",
556 type
=> 'string', format
=> 'pve-volume-id',
557 description
=> "Reference to a volume which stores the VM state. This is used internally for snapshots.",
559 vmstatestorage
=> get_standard_option
('pve-storage-id', {
560 description
=> "Default storage for VM state volumes/files.",
563 runningmachine
=> get_standard_option
('pve-qemu-machine', {
564 description
=> "Specifies the Qemu machine type of the running vm. This is used internally for snapshots.",
566 machine
=> get_standard_option
('pve-qemu-machine'),
568 description
=> "Virtual processor architecture. Defaults to the host.",
571 enum
=> [qw(x86_64 aarch64)],
574 description
=> "Specify SMBIOS type 1 fields.",
575 type
=> 'string', format
=> 'pve-qm-smbios1',
582 description
=> "Sets the protection flag of the VM. This will disable the remove VM and remove disk operations.",
588 enum
=> [ qw(seabios ovmf) ],
589 description
=> "Select BIOS implementation.",
590 default => 'seabios',
594 pattern
=> '(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])',
595 format_description
=> 'UUID',
596 description
=> "Set VM Generation ID. Use '1' to autogenerate on create or update, pass '0' to disable explicitly.",
597 verbose_description
=> "The VM generation ID (vmgenid) device exposes a".
598 " 128-bit integer value identifier to the guest OS. This allows to".
599 " notify the guest operating system when the virtual machine is".
600 " executed with a different configuration (e.g. snapshot execution".
601 " or creation from a template). The guest operating system notices".
602 " the change, and is then able to react as appropriate by marking".
603 " its copies of distributed databases as dirty, re-initializing its".
604 " random number generator, etc.\n".
605 "Note that auto-creation only works when done throug API/CLI create".
606 " or update methods, but not when manually editing the config file.",
607 default => "1 (autogenerated)",
612 my $confdesc_cloudinit = {
616 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.',
617 enum
=> ['configdrive2', 'nocloud'],
622 description
=> "cloud-init: User name to change ssh keys and password for instead of the image's configured default user.",
627 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.',
632 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.",
636 type
=> 'string', format
=> 'address-list',
637 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.",
642 format
=> 'urlencoded',
643 description
=> "cloud-init: Setup public SSH keys (one key per line, OpenSSH format).",
647 # what about other qemu settings ?
649 #machine => 'string',
662 ##soundhw => 'string',
664 while (my ($k, $v) = each %$confdesc) {
665 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
668 my $MAX_IDE_DISKS = 4;
669 my $MAX_SCSI_DISKS = 14;
670 my $MAX_VIRTIO_DISKS = 16;
671 my $MAX_SATA_DISKS = 6;
672 my $MAX_USB_DEVICES = 5;
674 my $MAX_UNUSED_DISKS = 256;
675 my $MAX_HOSTPCI_DEVICES = 4;
676 my $MAX_SERIAL_PORTS = 4;
677 my $MAX_PARALLEL_PORTS = 3;
683 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
684 description
=> "CPUs accessing this NUMA node.",
685 format_description
=> "id[-id];...",
689 description
=> "Amount of memory this NUMA node provides.",
694 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
695 description
=> "Host NUMA nodes to use.",
696 format_description
=> "id[-id];...",
701 enum
=> [qw(preferred bind interleave)],
702 description
=> "NUMA allocation policy.",
706 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
709 type
=> 'string', format
=> $numa_fmt,
710 description
=> "NUMA topology.",
712 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
714 for (my $i = 0; $i < $MAX_NUMA; $i++) {
715 $confdesc->{"numa$i"} = $numadesc;
718 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
719 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
720 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
721 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
723 my $net_fmt_bridge_descr = <<__EOD__;
724 Bridge to attach the network device to. The Proxmox VE standard bridge
727 If you do not specify a bridge, we create a kvm user (NATed) network
728 device, which provides DHCP and DNS services. The following addresses
735 The DHCP server assign addresses to the guest starting from 10.0.2.15.
741 pattern
=> qr/[0-9a-f]{2}(?::[0-9a-f]{2}){5}/i,
742 description
=> "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
743 format_description
=> "XX:XX:XX:XX:XX:XX",
748 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'.",
749 enum
=> $nic_model_list,
752 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
755 description
=> $net_fmt_bridge_descr,
756 format_description
=> 'bridge',
761 minimum
=> 0, maximum
=> 16,
762 description
=> 'Number of packet queues to be used on the device.',
768 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
773 minimum
=> 1, maximum
=> 4094,
774 description
=> 'VLAN tag to apply to packets on this interface.',
779 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
780 description
=> 'VLAN trunks to pass through this interface.',
781 format_description
=> 'vlanid[;vlanid...]',
786 description
=> 'Whether this interface should be protected by the firewall.',
791 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
798 type
=> 'string', format
=> $net_fmt,
799 description
=> "Specify network devices.",
802 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
807 format
=> 'pve-ipv4-config',
808 format_description
=> 'IPv4Format/CIDR',
809 description
=> 'IPv4 address in CIDR format.',
816 format_description
=> 'GatewayIPv4',
817 description
=> 'Default gateway for IPv4 traffic.',
823 format
=> 'pve-ipv6-config',
824 format_description
=> 'IPv6Format/CIDR',
825 description
=> 'IPv6 address in CIDR format.',
832 format_description
=> 'GatewayIPv6',
833 description
=> 'Default gateway for IPv6 traffic.',
838 PVE
::JSONSchema
::register_format
('pve-qm-ipconfig', $ipconfig_fmt);
841 type
=> 'string', format
=> 'pve-qm-ipconfig',
842 description
=> <<'EODESCR',
843 cloud-init: Specify IP addresses and gateways for the corresponding interface.
845 IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
847 The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided.
848 For IPv6 the special string 'auto' can be used to use stateless autoconfiguration.
850 If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4.
853 PVE
::JSONSchema
::register_standard_option
("pve-qm-ipconfig", $netdesc);
855 for (my $i = 0; $i < $MAX_NETS; $i++) {
856 $confdesc->{"net$i"} = $netdesc;
857 $confdesc_cloudinit->{"ipconfig$i"} = $ipconfigdesc;
860 foreach my $key (keys %$confdesc_cloudinit) {
861 $confdesc->{$key} = $confdesc_cloudinit->{$key};
864 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
865 sub verify_volume_id_or_qm_path
{
866 my ($volid, $noerr) = @_;
868 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
872 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
873 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
875 return undef if $noerr;
883 my %drivedesc_base = (
884 volume
=> { alias
=> 'file' },
887 format
=> 'pve-volume-id-or-qm-path',
889 format_description
=> 'volume',
890 description
=> "The drive's backing volume.",
894 enum
=> [qw(cdrom disk)],
895 description
=> "The drive's media type.",
901 description
=> "Force the drive's physical geometry to have a specific cylinder count.",
906 description
=> "Force the drive's physical geometry to have a specific head count.",
911 description
=> "Force the drive's physical geometry to have a specific sector count.",
916 enum
=> [qw(none lba auto)],
917 description
=> "Force disk geometry bios translation mode.",
922 description
=> "Controls qemu's snapshot mode feature."
923 . " If activated, changes made to the disk are temporary and will"
924 . " be discarded when the VM is shutdown.",
929 enum
=> [qw(none writethrough writeback unsafe directsync)],
930 description
=> "The drive's cache mode",
933 format
=> get_standard_option
('pve-qm-image-format'),
936 format
=> 'disk-size',
937 format_description
=> 'DiskSize',
938 description
=> "Disk size. This is purely informational and has no effect.",
943 description
=> "Whether the drive should be included when making backups.",
948 description
=> 'Whether the drive should considered for replication jobs.',
954 enum
=> [qw(ignore report stop)],
955 description
=> 'Read error action.',
960 enum
=> [qw(enospc ignore report stop)],
961 description
=> 'Write error action.',
966 enum
=> [qw(native threads)],
967 description
=> 'AIO type to use.',
972 enum
=> [qw(ignore on)],
973 description
=> 'Controls whether to pass discard/trim requests to the underlying storage.',
978 description
=> 'Controls whether to detect and try to optimize writes of zeroes.',
983 format
=> 'urlencoded',
984 format_description
=> 'serial',
985 maxLength
=> 20*3, # *3 since it's %xx url enoded
986 description
=> "The drive's reported serial number, url-encoded, up to 20 bytes long.",
991 description
=> 'Mark this locally-managed volume as available on all nodes',
992 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!",
998 my %iothread_fmt = ( iothread
=> {
1000 description
=> "Whether to use iothreads for this drive",
1007 format
=> 'urlencoded',
1008 format_description
=> 'model',
1009 maxLength
=> 40*3, # *3 since it's %xx url enoded
1010 description
=> "The drive's reported model name, url-encoded, up to 40 bytes long.",
1018 description
=> "Number of queues.",
1024 my %scsiblock_fmt = (
1027 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",
1036 description
=> "Whether to expose this drive as an SSD, rather than a rotational hard disk.",
1041 my $add_throttle_desc = sub {
1042 my ($key, $type, $what, $unit, $longunit, $minimum) = @_;
1045 format_description
=> $unit,
1046 description
=> "Maximum $what in $longunit.",
1049 $d->{minimum
} = $minimum if defined($minimum);
1050 $drivedesc_base{$key} = $d;
1052 # throughput: (leaky bucket)
1053 $add_throttle_desc->('bps', 'integer', 'r/w speed', 'bps', 'bytes per second');
1054 $add_throttle_desc->('bps_rd', 'integer', 'read speed', 'bps', 'bytes per second');
1055 $add_throttle_desc->('bps_wr', 'integer', 'write speed', 'bps', 'bytes per second');
1056 $add_throttle_desc->('mbps', 'number', 'r/w speed', 'mbps', 'megabytes per second');
1057 $add_throttle_desc->('mbps_rd', 'number', 'read speed', 'mbps', 'megabytes per second');
1058 $add_throttle_desc->('mbps_wr', 'number', 'write speed', 'mbps', 'megabytes per second');
1059 $add_throttle_desc->('iops', 'integer', 'r/w I/O', 'iops', 'operations per second');
1060 $add_throttle_desc->('iops_rd', 'integer', 'read I/O', 'iops', 'operations per second');
1061 $add_throttle_desc->('iops_wr', 'integer', 'write I/O', 'iops', 'operations per second');
1063 # pools: (pool of IO before throttling starts taking effect)
1064 $add_throttle_desc->('mbps_max', 'number', 'unthrottled r/w pool', 'mbps', 'megabytes per second');
1065 $add_throttle_desc->('mbps_rd_max', 'number', 'unthrottled read pool', 'mbps', 'megabytes per second');
1066 $add_throttle_desc->('mbps_wr_max', 'number', 'unthrottled write pool', 'mbps', 'megabytes per second');
1067 $add_throttle_desc->('iops_max', 'integer', 'unthrottled r/w I/O pool', 'iops', 'operations per second');
1068 $add_throttle_desc->('iops_rd_max', 'integer', 'unthrottled read I/O pool', 'iops', 'operations per second');
1069 $add_throttle_desc->('iops_wr_max', 'integer', 'unthrottled write I/O pool', 'iops', 'operations per second');
1072 $add_throttle_desc->('bps_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
1073 $add_throttle_desc->('bps_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
1074 $add_throttle_desc->('bps_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1075 $add_throttle_desc->('iops_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
1076 $add_throttle_desc->('iops_rd_max_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
1077 $add_throttle_desc->('iops_wr_max_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
1080 $drivedesc_base{'bps_rd_length'} = { alias
=> 'bps_rd_max_length' };
1081 $drivedesc_base{'bps_wr_length'} = { alias
=> 'bps_wr_max_length' };
1082 $drivedesc_base{'iops_rd_length'} = { alias
=> 'iops_rd_max_length' };
1083 $drivedesc_base{'iops_wr_length'} = { alias
=> 'iops_wr_max_length' };
1090 PVE
::JSONSchema
::register_format
("pve-qm-ide", $ide_fmt);
1094 type
=> 'string', format
=> $ide_fmt,
1095 description
=> "Use volume as IDE hard disk or CD-ROM (n is 0 to " .($MAX_IDE_DISKS -1) . ").",
1097 PVE
::JSONSchema
::register_standard_option
("pve-qm-ide", $idedesc);
1108 type
=> 'string', format
=> $scsi_fmt,
1109 description
=> "Use volume as SCSI hard disk or CD-ROM (n is 0 to " . ($MAX_SCSI_DISKS - 1) . ").",
1111 PVE
::JSONSchema
::register_standard_option
("pve-qm-scsi", $scsidesc);
1119 type
=> 'string', format
=> $sata_fmt,
1120 description
=> "Use volume as SATA hard disk or CD-ROM (n is 0 to " . ($MAX_SATA_DISKS - 1). ").",
1122 PVE
::JSONSchema
::register_standard_option
("pve-qm-sata", $satadesc);
1130 type
=> 'string', format
=> $virtio_fmt,
1131 description
=> "Use volume as VIRTIO hard disk (n is 0 to " . ($MAX_VIRTIO_DISKS - 1) . ").",
1133 PVE
::JSONSchema
::register_standard_option
("pve-qm-virtio", $virtiodesc);
1135 my $alldrive_fmt = {
1145 volume
=> { alias
=> 'file' },
1148 format
=> 'pve-volume-id-or-qm-path',
1150 format_description
=> 'volume',
1151 description
=> "The drive's backing volume.",
1153 format
=> get_standard_option
('pve-qm-image-format'),
1156 format
=> 'disk-size',
1157 format_description
=> 'DiskSize',
1158 description
=> "Disk size. This is purely informational and has no effect.",
1163 my $efidisk_desc = {
1165 type
=> 'string', format
=> $efidisk_fmt,
1166 description
=> "Configure a Disk for storing EFI vars",
1169 PVE
::JSONSchema
::register_standard_option
("pve-qm-efidisk", $efidisk_desc);
1174 type
=> 'string', format
=> 'pve-qm-usb-device',
1175 format_description
=> 'HOSTUSBDEVICE|spice',
1176 description
=> <<EODESCR,
1177 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
1179 'bus-port(.port)*' (decimal numbers) or
1180 'vendor_id:product_id' (hexadeciaml numbers) or
1183 You can use the 'lsusb -t' command to list existing usb devices.
1185 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1187 The value 'spice' can be used to add a usb redirection devices for spice.
1193 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).",
1200 type
=> 'string', format
=> $usb_fmt,
1201 description
=> "Configure an USB device (n is 0 to 4).",
1203 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
1205 my $PCIRE = qr/[a-f0-9]{2}:[a-f0-9]{2}(?:\.[a-f0-9])?/;
1210 pattern
=> qr/$PCIRE(;$PCIRE)*/,
1211 format_description
=> 'HOSTPCIID[;HOSTPCIID2...]',
1212 description
=> <<EODESCR,
1213 Host PCI device pass through. The PCI ID of a host's PCI device or a list
1214 of PCI virtual functions of the host. HOSTPCIID syntax is:
1216 'bus:dev.func' (hexadecimal numbers)
1218 You can us the 'lspci' command to list existing PCI devices.
1223 description
=> "Specify whether or not the device's ROM will be visible in the guest's memory map.",
1229 pattern
=> '[^,;]+',
1230 format_description
=> 'string',
1231 description
=> "Custom pci device rom filename (must be located in /usr/share/kvm/).",
1236 description
=> "Choose the PCI-express bus (needs the 'q35' machine model).",
1242 description
=> "Enable vfio-vga device support.",
1248 format_description
=> 'string',
1249 pattern
=> '[^/\.:]+',
1251 description
=> <<EODESCR
1252 The type of mediated device to use.
1253 An instance of this type will be created on startup of the VM and
1254 will be cleaned up when the VM stops.
1258 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', $hostpci_fmt);
1262 type
=> 'string', format
=> 'pve-qm-hostpci',
1263 description
=> "Map host PCI devices into guest.",
1264 verbose_description
=> <<EODESCR,
1265 Map host PCI devices into guest.
1267 NOTE: This option allows direct access to host hardware. So it is no longer
1268 possible to migrate such machines - use with special care.
1270 CAUTION: Experimental! User reported problems with this option.
1273 PVE
::JSONSchema
::register_standard_option
("pve-qm-hostpci", $hostpcidesc);
1278 pattern
=> '(/dev/.+|socket)',
1279 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1280 verbose_description
=> <<EODESCR,
1281 Create a serial device inside the VM (n is 0 to 3), and pass through a
1282 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1283 host side (use 'qm terminal' to open a terminal connection).
1285 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
1287 CAUTION: Experimental! User reported problems with this option.
1294 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1295 description
=> "Map host parallel devices (n is 0 to 2).",
1296 verbose_description
=> <<EODESCR,
1297 Map host parallel devices (n is 0 to 2).
1299 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1301 CAUTION: Experimental! User reported problems with this option.
1305 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1306 $confdesc->{"parallel$i"} = $paralleldesc;
1309 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1310 $confdesc->{"serial$i"} = $serialdesc;
1313 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
1314 $confdesc->{"hostpci$i"} = $hostpcidesc;
1317 for (my $i = 0; $i < $MAX_IDE_DISKS; $i++) {
1318 $drivename_hash->{"ide$i"} = 1;
1319 $confdesc->{"ide$i"} = $idedesc;
1322 for (my $i = 0; $i < $MAX_SATA_DISKS; $i++) {
1323 $drivename_hash->{"sata$i"} = 1;
1324 $confdesc->{"sata$i"} = $satadesc;
1327 for (my $i = 0; $i < $MAX_SCSI_DISKS; $i++) {
1328 $drivename_hash->{"scsi$i"} = 1;
1329 $confdesc->{"scsi$i"} = $scsidesc ;
1332 for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++) {
1333 $drivename_hash->{"virtio$i"} = 1;
1334 $confdesc->{"virtio$i"} = $virtiodesc;
1337 $drivename_hash->{efidisk0
} = 1;
1338 $confdesc->{efidisk0
} = $efidisk_desc;
1340 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1341 $confdesc->{"usb$i"} = $usbdesc;
1346 type
=> 'string', format
=> 'pve-volume-id',
1347 description
=> "Reference to unused volumes. This is used internally, and should not be modified manually.",
1350 for (my $i = 0; $i < $MAX_UNUSED_DISKS; $i++) {
1351 $confdesc->{"unused$i"} = $unuseddesc;
1354 my $kvm_api_version = 0;
1357 return $kvm_api_version if $kvm_api_version;
1359 open my $fh, '<', '/dev/kvm'
1362 # 0xae00 => KVM_GET_API_VERSION
1363 $kvm_api_version = ioctl($fh, 0xae00, 0);
1365 return $kvm_api_version;
1368 my $kvm_user_version;
1370 sub kvm_user_version
{
1372 return $kvm_user_version if $kvm_user_version;
1374 $kvm_user_version = 'unknown';
1378 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1379 $kvm_user_version = $2;
1383 eval { run_command
("kvm -version", outfunc
=> $code); };
1386 return $kvm_user_version;
1390 sub kernel_has_vhost_net
{
1391 return -c
'/dev/vhost-net';
1394 sub valid_drive_names
{
1395 # order is important - used to autoselect boot disk
1396 return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
1397 (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
1398 (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))),
1399 (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))),
1403 sub is_valid_drivename
{
1406 return defined($drivename_hash->{$dev});
1411 return defined($confdesc->{$key});
1415 return $nic_model_list;
1418 sub os_list_description
{
1422 wxp
=> 'Windows XP',
1423 w2k
=> 'Windows 2000',
1424 w2k3
=>, 'Windows 2003',
1425 w2k8
=> 'Windows 2008',
1426 wvista
=> 'Windows Vista',
1427 win7
=> 'Windows 7',
1428 win8
=> 'Windows 8/2012',
1429 win10
=> 'Windows 10/2016',
1437 sub get_cdrom_path
{
1439 return $cdrom_path if $cdrom_path;
1441 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1442 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1443 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1447 my ($storecfg, $vmid, $cdrom) = @_;
1449 if ($cdrom eq 'cdrom') {
1450 return get_cdrom_path
();
1451 } elsif ($cdrom eq 'none') {
1453 } elsif ($cdrom =~ m
|^/|) {
1456 return PVE
::Storage
::path
($storecfg, $cdrom);
1460 # try to convert old style file names to volume IDs
1461 sub filename_to_volume_id
{
1462 my ($vmid, $file, $media) = @_;
1464 if (!($file eq 'none' || $file eq 'cdrom' ||
1465 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1467 return undef if $file =~ m
|/|;
1469 if ($media && $media eq 'cdrom') {
1470 $file = "local:iso/$file";
1472 $file = "local:$vmid/$file";
1479 sub verify_media_type
{
1480 my ($opt, $vtype, $media) = @_;
1485 if ($media eq 'disk') {
1487 } elsif ($media eq 'cdrom') {
1490 die "internal error";
1493 return if ($vtype eq $etype);
1495 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1498 sub cleanup_drive_path
{
1499 my ($opt, $storecfg, $drive) = @_;
1501 # try to convert filesystem paths to volume IDs
1503 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1504 ($drive->{file
} !~ m
|^/dev/.+|) &&
1505 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1506 ($drive->{file
} !~ m/^\d+$/)) {
1507 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1508 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1509 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1510 verify_media_type
($opt, $vtype, $drive->{media
});
1511 $drive->{file
} = $volid;
1514 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1517 sub parse_hotplug_features
{
1522 return $res if $data eq '0';
1524 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1526 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1527 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1530 die "invalid hotplug feature '$feature'\n";
1536 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1537 sub pve_verify_hotplug_features
{
1538 my ($value, $noerr) = @_;
1540 return $value if parse_hotplug_features
($value);
1542 return undef if $noerr;
1544 die "unable to parse hotplug option\n";
1547 # ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
1548 # [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
1549 # [,rerror=ignore|report|stop][,werror=enospc|ignore|report|stop]
1550 # [,aio=native|threads][,discard=ignore|on][,detect_zeroes=on|off]
1551 # [,iothread=on][,serial=serial][,model=model]
1554 my ($key, $data) = @_;
1556 my ($interface, $index);
1558 if ($key =~ m/^([^\d]+)(\d+)$/) {
1565 my $desc = $key =~ /^unused\d+$/ ?
$alldrive_fmt
1566 : $confdesc->{$key}->{format
};
1568 warn "invalid drive key: $key\n";
1571 my $res = eval { PVE
::JSONSchema
::parse_property_string
($desc, $data) };
1572 return undef if !$res;
1573 $res->{interface
} = $interface;
1574 $res->{index} = $index;
1577 foreach my $opt (qw(bps bps_rd bps_wr)) {
1578 if (my $bps = defined(delete $res->{$opt})) {
1579 if (defined($res->{"m$opt"})) {
1580 warn "both $opt and m$opt specified\n";
1584 $res->{"m$opt"} = sprintf("%.3f", $bps / (1024*1024.0));
1588 # can't use the schema's 'requires' because of the mbps* => bps* "transforming aliases"
1589 for my $requirement (
1590 [mbps_max
=> 'mbps'],
1591 [mbps_rd_max
=> 'mbps_rd'],
1592 [mbps_wr_max
=> 'mbps_wr'],
1593 [miops_max
=> 'miops'],
1594 [miops_rd_max
=> 'miops_rd'],
1595 [miops_wr_max
=> 'miops_wr'],
1596 [bps_max_length
=> 'mbps_max'],
1597 [bps_rd_max_length
=> 'mbps_rd_max'],
1598 [bps_wr_max_length
=> 'mbps_wr_max'],
1599 [iops_max_length
=> 'iops_max'],
1600 [iops_rd_max_length
=> 'iops_rd_max'],
1601 [iops_wr_max_length
=> 'iops_wr_max']) {
1602 my ($option, $requires) = @$requirement;
1603 if ($res->{$option} && !$res->{$requires}) {
1604 warn "$option requires $requires\n";
1609 return undef if $error;
1611 return undef if $res->{mbps_rd
} && $res->{mbps
};
1612 return undef if $res->{mbps_wr
} && $res->{mbps
};
1613 return undef if $res->{iops_rd
} && $res->{iops
};
1614 return undef if $res->{iops_wr
} && $res->{iops
};
1616 if ($res->{media
} && ($res->{media
} eq 'cdrom')) {
1617 return undef if $res->{snapshot
} || $res->{trans
} || $res->{format
};
1618 return undef if $res->{heads
} || $res->{secs
} || $res->{cyls
};
1619 return undef if $res->{interface
} eq 'virtio';
1622 if (my $size = $res->{size
}) {
1623 return undef if !defined($res->{size
} = PVE
::JSONSchema
::parse_size
($size));
1630 my ($vmid, $drive) = @_;
1631 my $data = { %$drive };
1632 delete $data->{$_} for qw(index interface);
1633 return PVE
::JSONSchema
::print_property_string
($data, $alldrive_fmt);
1637 my($fh, $noerr) = @_;
1640 my $SG_GET_VERSION_NUM = 0x2282;
1642 my $versionbuf = "\x00" x
8;
1643 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1645 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1648 my $version = unpack("I", $versionbuf);
1649 if ($version < 30000) {
1650 die "scsi generic interface too old\n" if !$noerr;
1654 my $buf = "\x00" x
36;
1655 my $sensebuf = "\x00" x
8;
1656 my $cmd = pack("C x3 C x1", 0x12, 36);
1658 # see /usr/include/scsi/sg.h
1659 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";
1661 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1662 length($sensebuf), 0, length($buf), $buf,
1663 $cmd, $sensebuf, 6000);
1665 $ret = ioctl($fh, $SG_IO, $packet);
1667 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1671 my @res = unpack($sg_io_hdr_t, $packet);
1672 if ($res[17] || $res[18]) {
1673 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1678 (my $byte0, my $byte1, $res->{vendor
},
1679 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1681 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1682 $res->{type
} = $byte0 & 31;
1690 my $fh = IO
::File-
>new("+<$path") || return undef;
1691 my $res = scsi_inquiry
($fh, 1);
1697 sub machine_type_is_q35
{
1700 return $conf->{machine
} && ($conf->{machine
} =~ m/q35/) ?
1 : 0;
1703 sub print_tabletdevice_full
{
1704 my ($conf, $arch) = @_;
1706 my $q35 = machine_type_is_q35
($conf);
1708 # we use uhci for old VMs because tablet driver was buggy in older qemu
1710 if (machine_type_is_q35
($conf) || $arch eq 'aarch64') {
1716 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1719 sub print_keyboarddevice_full
{
1720 my ($conf, $arch, $machine) = @_;
1722 return undef if $arch ne 'aarch64';
1724 return "usb-kbd,id=keyboard,bus=ehci.0,port=2";
1727 sub print_drivedevice_full
{
1728 my ($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type) = @_;
1733 if ($drive->{interface
} eq 'virtio') {
1734 my $pciaddr = print_pci_addr
("$drive->{interface}$drive->{index}", $bridges, $arch, $machine_type);
1735 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1736 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread
};
1737 } elsif ($drive->{interface
} eq 'scsi') {
1739 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1740 my $unit = $drive->{index} % $maxdev;
1741 my $devicetype = 'hd';
1743 if (drive_is_cdrom
($drive)) {
1746 if ($drive->{file
} =~ m
|^/|) {
1747 $path = $drive->{file
};
1748 if (my $info = path_is_scsi
($path)) {
1749 if ($info->{type
} == 0 && $drive->{scsiblock
}) {
1750 $devicetype = 'block';
1751 } elsif ($info->{type
} == 1) { # tape
1752 $devicetype = 'generic';
1756 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1759 if($path =~ m/^iscsi\:\/\
//){
1760 $devicetype = 'generic';
1764 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1765 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1767 $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}";
1770 if ($drive->{ssd
} && ($devicetype eq 'block' || $devicetype eq 'hd')) {
1771 $device .= ",rotation_rate=1";
1774 } elsif ($drive->{interface
} eq 'ide' || $drive->{interface
} eq 'sata') {
1775 my $maxdev = ($drive->{interface
} eq 'sata') ?
$MAX_SATA_DISKS : 2;
1776 my $controller = int($drive->{index} / $maxdev);
1777 my $unit = $drive->{index} % $maxdev;
1778 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1780 $device = "ide-$devicetype";
1781 if ($drive->{interface
} eq 'ide') {
1782 $device .= ",bus=ide.$controller,unit=$unit";
1784 $device .= ",bus=ahci$controller.$unit";
1786 $device .= ",drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1788 if ($devicetype eq 'hd') {
1789 if (my $model = $drive->{model
}) {
1790 $model = URI
::Escape
::uri_unescape
($model);
1791 $device .= ",model=$model";
1793 if ($drive->{ssd
}) {
1794 $device .= ",rotation_rate=1";
1797 } elsif ($drive->{interface
} eq 'usb') {
1799 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1801 die "unsupported interface type";
1804 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1806 if (my $serial = $drive->{serial
}) {
1807 $serial = URI
::Escape
::uri_unescape
($serial);
1808 $device .= ",serial=$serial";
1815 sub get_initiator_name
{
1818 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return undef;
1819 while (defined(my $line = <$fh>)) {
1820 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1829 sub print_drive_full
{
1830 my ($storecfg, $vmid, $drive) = @_;
1833 my $volid = $drive->{file
};
1836 if (drive_is_cdrom
($drive)) {
1837 $path = get_iso_path
($storecfg, $vmid, $volid);
1839 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1841 $path = PVE
::Storage
::path
($storecfg, $volid);
1842 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1843 $format = qemu_img_format
($scfg, $volname);
1851 my @qemu_drive_options = qw(heads secs cyls trans media format cache rerror werror aio discard);
1852 foreach my $o (@qemu_drive_options) {
1853 $opts .= ",$o=$drive->{$o}" if defined($drive->{$o});
1856 # snapshot only accepts on|off
1857 if (defined($drive->{snapshot
})) {
1858 my $v = $drive->{snapshot
} ?
'on' : 'off';
1859 $opts .= ",snapshot=$v";
1862 foreach my $type (['', '-total'], [_rd
=> '-read'], [_wr
=> '-write']) {
1863 my ($dir, $qmpname) = @$type;
1864 if (my $v = $drive->{"mbps$dir"}) {
1865 $opts .= ",throttling.bps$qmpname=".int($v*1024*1024);
1867 if (my $v = $drive->{"mbps${dir}_max"}) {
1868 $opts .= ",throttling.bps$qmpname-max=".int($v*1024*1024);
1870 if (my $v = $drive->{"bps${dir}_max_length"}) {
1871 $opts .= ",throttling.bps$qmpname-max-length=$v";
1873 if (my $v = $drive->{"iops${dir}"}) {
1874 $opts .= ",throttling.iops$qmpname=$v";
1876 if (my $v = $drive->{"iops${dir}_max"}) {
1877 $opts .= ",throttling.iops$qmpname-max=$v";
1879 if (my $v = $drive->{"iops${dir}_max_length"}) {
1880 $opts .= ",throttling.iops$qmpname-max-length=$v";
1884 $opts .= ",format=$format" if $format && !$drive->{format
};
1886 my $cache_direct = 0;
1888 if (my $cache = $drive->{cache
}) {
1889 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1890 } elsif (!drive_is_cdrom
($drive)) {
1891 $opts .= ",cache=none";
1895 # aio native works only with O_DIRECT
1896 if (!$drive->{aio
}) {
1898 $opts .= ",aio=native";
1900 $opts .= ",aio=threads";
1904 if (!drive_is_cdrom
($drive)) {
1906 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1907 $detectzeroes = 'off';
1908 } elsif ($drive->{discard
}) {
1909 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1911 # This used to be our default with discard not being specified:
1912 $detectzeroes = 'on';
1914 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1917 my $pathinfo = $path ?
"file=$path," : '';
1919 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1922 sub print_netdevice_full
{
1923 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files, $arch, $machine_type) = @_;
1925 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
1927 my $device = $net->{model
};
1928 if ($net->{model
} eq 'virtio') {
1929 $device = 'virtio-net-pci';
1932 my $pciaddr = print_pci_addr
("$netid", $bridges, $arch, $machine_type);
1933 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1934 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1935 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1936 my $vectors = $net->{queues
} * 2 + 2;
1937 $tmpstr .= ",vectors=$vectors,mq=on";
1939 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1941 if ($use_old_bios_files) {
1943 if ($device eq 'virtio-net-pci') {
1944 $romfile = 'pxe-virtio.rom';
1945 } elsif ($device eq 'e1000') {
1946 $romfile = 'pxe-e1000.rom';
1947 } elsif ($device eq 'ne2k') {
1948 $romfile = 'pxe-ne2k_pci.rom';
1949 } elsif ($device eq 'pcnet') {
1950 $romfile = 'pxe-pcnet.rom';
1951 } elsif ($device eq 'rtl8139') {
1952 $romfile = 'pxe-rtl8139.rom';
1954 $tmpstr .= ",romfile=$romfile" if $romfile;
1960 sub print_netdev_full
{
1961 my ($vmid, $conf, $arch, $net, $netid, $hotplug) = @_;
1964 if ($netid =~ m/^net(\d+)$/) {
1968 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1970 my $ifname = "tap${vmid}i$i";
1972 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1973 die "interface name '$ifname' is too long (max 15 character)\n"
1974 if length($ifname) >= 16;
1976 my $vhostparam = '';
1977 if (is_native
($arch)) {
1978 $vhostparam = ',vhost=on' if kernel_has_vhost_net
() && $net->{model
} eq 'virtio';
1981 my $vmname = $conf->{name
} || "vm$vmid";
1984 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1986 if ($net->{bridge
}) {
1987 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1989 $netdev = "type=user,id=$netid,hostname=$vmname";
1992 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1998 sub print_cpu_device
{
1999 my ($conf, $id) = @_;
2001 my $kvm = $conf->{kvm
} // 1;
2002 my $cpu = $kvm ?
"kvm64" : "qemu64";
2003 if (my $cputype = $conf->{cpu
}) {
2004 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
2005 or die "Cannot parse cpu description: $cputype\n";
2006 $cpu = $cpuconf->{cputype
};
2009 my $cores = $conf->{cores
} || 1;
2011 my $current_core = ($id - 1) % $cores;
2012 my $current_socket = int(($id - 1 - $current_core)/$cores);
2014 return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
2018 'cirrus' => 'cirrus-vga',
2020 'vmware' => 'vmware-svga',
2021 'virtio' => 'virtio-vga',
2024 sub print_vga_device
{
2025 my ($conf, $vga, $arch, $machine, $id, $qxlnum, $bridges) = @_;
2027 my $type = $vga_map->{$vga->{type
}};
2028 if ($arch eq 'aarch64' && defined($type) && $type eq 'virtio-vga') {
2029 $type = 'virtio-gpu';
2031 my $vgamem_mb = $vga->{memory
};
2033 $type = $id ?
'qxl' : 'qxl-vga';
2035 die "no devicetype for $vga->{type}\n" if !$type;
2039 if ($vga->{type
} eq 'virtio') {
2040 my $bytes = PVE
::Tools
::convert_size
($vgamem_mb, "mb" => "b");
2041 $memory = ",max_hostmem=$bytes";
2043 # from https://www.spice-space.org/multiple-monitors.html
2044 $memory = ",vgamem_mb=$vga->{memory}";
2045 my $ram = $vgamem_mb * 4;
2046 my $vram = $vgamem_mb * 2;
2047 $memory .= ",ram_size_mb=$ram,vram_size_mb=$vram";
2049 $memory = ",vgamem_mb=$vga->{memory}";
2051 } elsif ($qxlnum && $id) {
2052 $memory = ",ram_size=67108864,vram_size=33554432";
2055 my $q35 = machine_type_is_q35
($conf);
2056 my $vgaid = "vga" . ($id // '');
2059 if ($q35 && $vgaid eq 'vga') {
2060 # the first display uses pcie.0 bus on q35 machines
2061 $pciaddr = print_pcie_addr
($vgaid, $bridges, $arch, $machine);
2063 $pciaddr = print_pci_addr
($vgaid, $bridges, $arch, $machine);
2066 return "$type,id=${vgaid}${memory}${pciaddr}";
2069 sub drive_is_cloudinit
{
2071 return $drive->{file
} =~ m
@[:/]vm-\d
+-cloudinit
(?
:\
.$QEMU_FORMAT_RE)?
$@;
2074 sub drive_is_cdrom
{
2075 my ($drive, $exclude_cloudinit) = @_;
2077 return 0 if $exclude_cloudinit && drive_is_cloudinit
($drive);
2079 return $drive && $drive->{media
} && ($drive->{media
} eq 'cdrom');
2083 sub parse_number_sets
{
2086 foreach my $part (split(/;/, $set)) {
2087 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
2088 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
2089 push @$res, [ $1, $2 ];
2091 die "invalid range: $part\n";
2100 my $res = PVE
::JSONSchema
::parse_property_string
($numa_fmt, $data);
2101 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
2102 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
2109 return undef if !$value;
2111 my $res = PVE
::JSONSchema
::parse_property_string
($hostpci_fmt, $value);
2113 my @idlist = split(/;/, $res->{host
});
2114 delete $res->{host
};
2115 foreach my $id (@idlist) {
2116 if ($id =~ m/\./) { # full id 00:00.1
2117 push @{$res->{pciid
}}, {
2120 } else { # partial id 00:00
2121 $res->{pciid
} = PVE
::SysFSTools
::lspci
($id);
2127 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
2131 my $res = eval { PVE
::JSONSchema
::parse_property_string
($net_fmt, $data) };
2136 if (!defined($res->{macaddr
})) {
2137 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
2138 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
2143 # ipconfigX ip=cidr,gw=ip,ip6=cidr,gw6=ip
2144 sub parse_ipconfig
{
2147 my $res = eval { PVE
::JSONSchema
::parse_property_string
($ipconfig_fmt, $data) };
2153 if ($res->{gw
} && !$res->{ip
}) {
2154 warn 'gateway specified without specifying an IP address';
2157 if ($res->{gw6
} && !$res->{ip6
}) {
2158 warn 'IPv6 gateway specified without specifying an IPv6 address';
2161 if ($res->{gw
} && $res->{ip
} eq 'dhcp') {
2162 warn 'gateway specified together with DHCP';
2165 if ($res->{gw6
} && $res->{ip6
} !~ /^$IPV6RE/) {
2167 warn "IPv6 gateway specified together with $res->{ip6} address";
2171 if (!$res->{ip
} && !$res->{ip6
}) {
2172 return { ip
=> 'dhcp', ip6
=> 'dhcp' };
2181 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
2184 sub add_random_macs
{
2185 my ($settings) = @_;
2187 foreach my $opt (keys %$settings) {
2188 next if $opt !~ m/^net(\d+)$/;
2189 my $net = parse_net
($settings->{$opt});
2191 $settings->{$opt} = print_net
($net);
2195 sub vm_is_volid_owner
{
2196 my ($storecfg, $vmid, $volid) = @_;
2198 if ($volid !~ m
|^/|) {
2200 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
2201 if ($owner && ($owner == $vmid)) {
2209 sub split_flagged_list
{
2210 my $text = shift || '';
2211 $text =~ s/[,;]/ /g;
2213 return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
2216 sub join_flagged_list
{
2217 my ($how, $lst) = @_;
2218 join $how, map { $lst->{$_} . $_ } keys %$lst;
2221 sub vmconfig_delete_pending_option
{
2222 my ($conf, $key, $force) = @_;
2224 delete $conf->{pending
}->{$key};
2225 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2226 $pending_delete_hash->{$key} = $force ?
'!' : '';
2227 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2230 sub vmconfig_undelete_pending_option
{
2231 my ($conf, $key) = @_;
2233 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2234 delete $pending_delete_hash->{$key};
2236 if (%$pending_delete_hash) {
2237 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2239 delete $conf->{pending
}->{delete};
2243 sub vmconfig_register_unused_drive
{
2244 my ($storecfg, $vmid, $conf, $drive) = @_;
2246 if (drive_is_cloudinit
($drive)) {
2247 eval { PVE
::Storage
::vdisk_free
($storecfg, $drive->{file
}) };
2249 } elsif (!drive_is_cdrom
($drive)) {
2250 my $volid = $drive->{file
};
2251 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
2252 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
2257 sub vmconfig_cleanup_pending
{
2260 # remove pending changes when nothing changed
2262 foreach my $opt (keys %{$conf->{pending
}}) {
2263 if (defined($conf->{$opt}) && ($conf->{pending
}->{$opt} eq $conf->{$opt})) {
2265 delete $conf->{pending
}->{$opt};
2269 my $current_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
2270 my $pending_delete_hash = {};
2271 while (my ($opt, $force) = each %$current_delete_hash) {
2272 if (defined($conf->{$opt})) {
2273 $pending_delete_hash->{$opt} = $force;
2279 if (%$pending_delete_hash) {
2280 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
2282 delete $conf->{pending
}->{delete};
2288 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
2292 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
2293 format_description
=> 'UUID',
2294 description
=> "Set SMBIOS1 UUID.",
2300 format_description
=> 'string',
2301 description
=> "Set SMBIOS1 version.",
2307 format_description
=> 'string',
2308 description
=> "Set SMBIOS1 serial number.",
2314 format_description
=> 'string',
2315 description
=> "Set SMBIOS1 manufacturer.",
2321 format_description
=> 'string',
2322 description
=> "Set SMBIOS1 product ID.",
2328 format_description
=> 'string',
2329 description
=> "Set SMBIOS1 SKU string.",
2335 format_description
=> 'string',
2336 description
=> "Set SMBIOS1 family string.",
2344 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_fmt, $data) };
2351 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
2354 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
2356 PVE
::JSONSchema
::register_format
('pve-qm-bootdisk', \
&verify_bootdisk
);
2357 sub verify_bootdisk
{
2358 my ($value, $noerr) = @_;
2360 return $value if is_valid_drivename
($value);
2362 return undef if $noerr;
2364 die "invalid boot disk '$value'\n";
2367 sub parse_watchdog
{
2370 return undef if !$value;
2372 my $res = eval { PVE
::JSONSchema
::parse_property_string
($watchdog_fmt, $value) };
2377 sub parse_guest_agent
{
2380 return {} if !defined($value->{agent
});
2382 my $res = eval { PVE
::JSONSchema
::parse_property_string
($agent_fmt, $value->{agent
}) };
2385 # if the agent is disabled ignore the other potentially set properties
2386 return {} if !$res->{enabled
};
2393 return {} if !$value;
2394 my $res = eval { PVE
::JSONSchema
::parse_property_string
($vga_fmt, $value) };
2399 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
2400 sub verify_usb_device
{
2401 my ($value, $noerr) = @_;
2403 return $value if parse_usb_device
($value);
2405 return undef if $noerr;
2407 die "unable to parse usb device\n";
2410 # add JSON properties for create and set function
2411 sub json_config_properties
{
2414 foreach my $opt (keys %$confdesc) {
2415 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate' || $opt eq 'runningmachine';
2416 $prop->{$opt} = $confdesc->{$opt};
2422 # return copy of $confdesc_cloudinit to generate documentation
2423 sub cloudinit_config_properties
{
2425 return dclone
($confdesc_cloudinit);
2429 my ($key, $value) = @_;
2431 die "unknown setting '$key'\n" if !$confdesc->{$key};
2433 my $type = $confdesc->{$key}->{type
};
2435 if (!defined($value)) {
2436 die "got undefined value\n";
2439 if ($value =~ m/[\n\r]/) {
2440 die "property contains a line feed\n";
2443 if ($type eq 'boolean') {
2444 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2445 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2446 die "type check ('boolean') failed - got '$value'\n";
2447 } elsif ($type eq 'integer') {
2448 return int($1) if $value =~ m/^(\d+)$/;
2449 die "type check ('integer') failed - got '$value'\n";
2450 } elsif ($type eq 'number') {
2451 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2452 die "type check ('number') failed - got '$value'\n";
2453 } elsif ($type eq 'string') {
2454 if (my $fmt = $confdesc->{$key}->{format
}) {
2455 PVE
::JSONSchema
::check_format
($fmt, $value);
2458 $value =~ s/^\"(.*)\"$/$1/;
2461 die "internal error"
2468 my $conf = PVE
::QemuConfig-
>config_file($vmid);
2469 utime undef, undef, $conf;
2473 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
2475 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
2477 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2479 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2481 if ($conf->{template
}) {
2482 # check if any base image is still used by a linked clone
2483 foreach_drive
($conf, sub {
2484 my ($ds, $drive) = @_;
2486 return if drive_is_cdrom
($drive);
2488 my $volid = $drive->{file
};
2490 return if !$volid || $volid =~ m
|^/|;
2492 die "base volume '$volid' is still in use by linked cloned\n"
2493 if PVE
::Storage
::volume_is_base_and_used
($storecfg, $volid);
2498 # only remove disks owned by this VM
2499 foreach_drive
($conf, sub {
2500 my ($ds, $drive) = @_;
2502 return if drive_is_cdrom
($drive, 1);
2504 my $volid = $drive->{file
};
2506 return if !$volid || $volid =~ m
|^/|;
2508 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2509 return if !$path || !$owner || ($owner != $vmid);
2512 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2514 warn "Could not remove disk '$volid', check manually: $@" if $@;
2518 if ($keep_empty_config) {
2519 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
2524 # also remove unused disk
2526 my $dl = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
2529 PVE
::Storage
::foreach_volid
($dl, sub {
2530 my ($volid, $sid, $volname, $d) = @_;
2531 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2540 sub parse_vm_config
{
2541 my ($filename, $raw) = @_;
2543 return undef if !defined($raw);
2546 digest
=> Digest
::SHA
::sha1_hex
($raw),
2551 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2552 || die "got strange filename '$filename'";
2560 my @lines = split(/\n/, $raw);
2561 foreach my $line (@lines) {
2562 next if $line =~ m/^\s*$/;
2564 if ($line =~ m/^\[PENDING\]\s*$/i) {
2565 $section = 'pending';
2566 if (defined($descr)) {
2568 $conf->{description
} = $descr;
2571 $conf = $res->{$section} = {};
2574 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2576 if (defined($descr)) {
2578 $conf->{description
} = $descr;
2581 $conf = $res->{snapshots
}->{$section} = {};
2585 if ($line =~ m/^\#(.*)\s*$/) {
2586 $descr = '' if !defined($descr);
2587 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2591 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2592 $descr = '' if !defined($descr);
2593 $descr .= PVE
::Tools
::decode_text
($2);
2594 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2595 $conf->{snapstate
} = $1;
2596 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2599 $conf->{$key} = $value;
2600 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2602 if ($section eq 'pending') {
2603 $conf->{delete} = $value; # we parse this later
2605 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2607 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(.+?)\s*$/) {
2610 eval { $value = check_type
($key, $value); };
2612 warn "vm $vmid - unable to parse value of '$key' - $@";
2614 $key = 'ide2' if $key eq 'cdrom';
2615 my $fmt = $confdesc->{$key}->{format
};
2616 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2617 my $v = parse_drive
($key, $value);
2618 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2619 $v->{file
} = $volid;
2620 $value = print_drive
($vmid, $v);
2622 warn "vm $vmid - unable to parse value of '$key'\n";
2627 $conf->{$key} = $value;
2632 if (defined($descr)) {
2634 $conf->{description
} = $descr;
2636 delete $res->{snapstate
}; # just to be sure
2641 sub write_vm_config
{
2642 my ($filename, $conf) = @_;
2644 delete $conf->{snapstate
}; # just to be sure
2646 if ($conf->{cdrom
}) {
2647 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2648 $conf->{ide2
} = $conf->{cdrom
};
2649 delete $conf->{cdrom
};
2652 # we do not use 'smp' any longer
2653 if ($conf->{sockets
}) {
2654 delete $conf->{smp
};
2655 } elsif ($conf->{smp
}) {
2656 $conf->{sockets
} = $conf->{smp
};
2657 delete $conf->{cores
};
2658 delete $conf->{smp
};
2661 my $used_volids = {};
2663 my $cleanup_config = sub {
2664 my ($cref, $pending, $snapname) = @_;
2666 foreach my $key (keys %$cref) {
2667 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2668 $key eq 'snapstate' || $key eq 'pending';
2669 my $value = $cref->{$key};
2670 if ($key eq 'delete') {
2671 die "propertry 'delete' is only allowed in [PENDING]\n"
2673 # fixme: check syntax?
2676 eval { $value = check_type
($key, $value); };
2677 die "unable to parse value of '$key' - $@" if $@;
2679 $cref->{$key} = $value;
2681 if (!$snapname && is_valid_drivename
($key)) {
2682 my $drive = parse_drive
($key, $value);
2683 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2688 &$cleanup_config($conf);
2690 &$cleanup_config($conf->{pending
}, 1);
2692 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2693 die "internal error" if $snapname eq 'pending';
2694 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2697 # remove 'unusedX' settings if we re-add a volume
2698 foreach my $key (keys %$conf) {
2699 my $value = $conf->{$key};
2700 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2701 delete $conf->{$key};
2705 my $generate_raw_config = sub {
2706 my ($conf, $pending) = @_;
2710 # add description as comment to top of file
2711 if (defined(my $descr = $conf->{description
})) {
2713 foreach my $cl (split(/\n/, $descr)) {
2714 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2717 $raw .= "#\n" if $pending;
2721 foreach my $key (sort keys %$conf) {
2722 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2723 $raw .= "$key: $conf->{$key}\n";
2728 my $raw = &$generate_raw_config($conf);
2730 if (scalar(keys %{$conf->{pending
}})){
2731 $raw .= "\n[PENDING]\n";
2732 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2735 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2736 $raw .= "\n[$snapname]\n";
2737 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2747 # we use static defaults from our JSON schema configuration
2748 foreach my $key (keys %$confdesc) {
2749 if (defined(my $default = $confdesc->{$key}->{default})) {
2750 $res->{$key} = $default;
2758 my $vmlist = PVE
::Cluster
::get_vmlist
();
2760 return $res if !$vmlist || !$vmlist->{ids
};
2761 my $ids = $vmlist->{ids
};
2763 foreach my $vmid (keys %$ids) {
2764 my $d = $ids->{$vmid};
2765 next if !$d->{node
} || $d->{node
} ne $nodename;
2766 next if !$d->{type
} || $d->{type
} ne 'qemu';
2767 $res->{$vmid}->{exists} = 1;
2772 # test if VM uses local resources (to prevent migration)
2773 sub check_local_resources
{
2774 my ($conf, $noerr) = @_;
2778 $loc_res = 1 if $conf->{hostusb
}; # old syntax
2779 $loc_res = 1 if $conf->{hostpci
}; # old syntax
2781 foreach my $k (keys %$conf) {
2782 next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2783 # sockets are safe: they will recreated be on the target side post-migrate
2784 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2785 $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2788 die "VM uses local resources\n" if $loc_res && !$noerr;
2793 # check if used storages are available on all nodes (use by migrate)
2794 sub check_storage_availability
{
2795 my ($storecfg, $conf, $node) = @_;
2797 foreach_drive
($conf, sub {
2798 my ($ds, $drive) = @_;
2800 my $volid = $drive->{file
};
2803 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2806 # check if storage is available on both nodes
2807 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2808 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2812 # list nodes where all VM images are available (used by has_feature API)
2814 my ($conf, $storecfg) = @_;
2816 my $nodelist = PVE
::Cluster
::get_nodelist
();
2817 my $nodehash = { map { $_ => 1 } @$nodelist };
2818 my $nodename = PVE
::INotify
::nodename
();
2820 foreach_drive
($conf, sub {
2821 my ($ds, $drive) = @_;
2823 my $volid = $drive->{file
};
2826 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2828 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2829 if ($scfg->{disable
}) {
2831 } elsif (my $avail = $scfg->{nodes
}) {
2832 foreach my $node (keys %$nodehash) {
2833 delete $nodehash->{$node} if !$avail->{$node};
2835 } elsif (!$scfg->{shared
}) {
2836 foreach my $node (keys %$nodehash) {
2837 delete $nodehash->{$node} if $node ne $nodename
2847 my ($pidfile, $pid) = @_;
2849 my $fh = IO
::File-
>new("/proc/$pid/cmdline", "r");
2853 return undef if !$line;
2854 my @param = split(/\0/, $line);
2856 my $cmd = $param[0];
2857 return if !$cmd || ($cmd !~ m
|kvm
$| && $cmd !~ m
@(?
:^|/)qemu-system-[^/]+$@);
2859 for (my $i = 0; $i < scalar (@param); $i++) {
2862 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2863 my $p = $param[$i+1];
2864 return 1 if $p && ($p eq $pidfile);
2873 my ($vmid, $nocheck, $node) = @_;
2875 my $filename = PVE
::QemuConfig-
>config_file($vmid, $node);
2877 die "unable to find configuration file for VM $vmid - no such machine\n"
2878 if !$nocheck && ! -f
$filename;
2880 my $pidfile = pidfile_name
($vmid);
2882 if (my $fd = IO
::File-
>new("<$pidfile")) {
2887 my $mtime = $st->mtime;
2888 if ($mtime > time()) {
2889 warn "file '$filename' modified in future\n";
2892 if ($line =~ m/^(\d+)$/) {
2894 if (check_cmdline
($pidfile, $pid)) {
2895 if (my $pinfo = PVE
::ProcFSTools
::check_process_running
($pid)) {
2907 my $vzlist = config_list
();
2909 my $fd = IO
::Dir-
>new($var_run_tmpdir) || return $vzlist;
2911 while (defined(my $de = $fd->read)) {
2912 next if $de !~ m/^(\d+)\.pid$/;
2914 next if !defined($vzlist->{$vmid});
2915 if (my $pid = check_running
($vmid)) {
2916 $vzlist->{$vmid}->{pid
} = $pid;
2924 my ($storecfg, $conf) = @_;
2926 my $bootdisk = $conf->{bootdisk
};
2927 return undef if !$bootdisk;
2928 return undef if !is_valid_drivename
($bootdisk);
2930 return undef if !$conf->{$bootdisk};
2932 my $drive = parse_drive
($bootdisk, $conf->{$bootdisk});
2933 return undef if !defined($drive);
2935 return undef if drive_is_cdrom
($drive);
2937 my $volid = $drive->{file
};
2938 return undef if !$volid;
2940 return $drive->{size
};
2943 our $vmstatus_return_properties = {
2944 vmid
=> get_standard_option
('pve-vmid'),
2946 description
=> "Qemu process status.",
2948 enum
=> ['stopped', 'running'],
2951 description
=> "Maximum memory in bytes.",
2954 renderer
=> 'bytes',
2957 description
=> "Root disk size in bytes.",
2960 renderer
=> 'bytes',
2963 description
=> "VM name.",
2968 description
=> "Qemu QMP agent status.",
2973 description
=> "PID of running qemu process.",
2978 description
=> "Uptime.",
2981 renderer
=> 'duration',
2984 description
=> "Maximum usable CPUs.",
2990 my $last_proc_pid_stat;
2992 # get VM status information
2993 # This must be fast and should not block ($full == false)
2994 # We only query KVM using QMP if $full == true (this can be slow)
2996 my ($opt_vmid, $full) = @_;
3000 my $storecfg = PVE
::Storage
::config
();
3002 my $list = vzlist
();
3003 my $defaults = load_defaults
();
3005 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
3007 my $cpucount = $cpuinfo->{cpus
} || 1;
3009 foreach my $vmid (keys %$list) {
3010 next if $opt_vmid && ($vmid ne $opt_vmid);
3012 my $cfspath = PVE
::QemuConfig-
>cfs_config_path($vmid);
3013 my $conf = PVE
::Cluster
::cfs_read_file
($cfspath) || {};
3015 my $d = { vmid
=> $vmid };
3016 $d->{pid
} = $list->{$vmid}->{pid
};
3018 # fixme: better status?
3019 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
3021 my $size = disksize
($storecfg, $conf);
3022 if (defined($size)) {
3023 $d->{disk
} = 0; # no info available
3024 $d->{maxdisk
} = $size;
3030 $d->{cpus
} = ($conf->{sockets
} || $defaults->{sockets
})
3031 * ($conf->{cores
} || $defaults->{cores
});
3032 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
3033 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
3035 $d->{name
} = $conf->{name
} || "VM $vmid";
3036 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024)
3037 : $defaults->{memory
}*(1024*1024);
3039 if ($conf->{balloon
}) {
3040 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
3041 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
}
3042 : $defaults->{shares
};
3053 $d->{diskwrite
} = 0;
3055 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
3057 $d->{serial
} = 1 if conf_has_serial
($conf);
3062 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
3063 foreach my $dev (keys %$netdev) {
3064 next if $dev !~ m/^tap([1-9]\d*)i/;
3066 my $d = $res->{$vmid};
3069 $d->{netout
} += $netdev->{$dev}->{receive
};
3070 $d->{netin
} += $netdev->{$dev}->{transmit
};
3073 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
3074 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
3079 my $ctime = gettimeofday
;
3081 foreach my $vmid (keys %$list) {
3083 my $d = $res->{$vmid};
3084 my $pid = $d->{pid
};
3087 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
3088 next if !$pstat; # not running
3090 my $used = $pstat->{utime} + $pstat->{stime
};
3092 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
3094 if ($pstat->{vsize
}) {
3095 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
3098 my $old = $last_proc_pid_stat->{$pid};
3100 $last_proc_pid_stat->{$pid} = {
3108 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
3110 if ($dtime > 1000) {
3111 my $dutime = $used - $old->{used
};
3113 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
3114 $last_proc_pid_stat->{$pid} = {
3120 $d->{cpu
} = $old->{cpu
};
3124 return $res if !$full;
3126 my $qmpclient = PVE
::QMPClient-
>new();
3128 my $ballooncb = sub {
3129 my ($vmid, $resp) = @_;
3131 my $info = $resp->{'return'};
3132 return if !$info->{max_mem
};
3134 my $d = $res->{$vmid};
3136 # use memory assigned to VM
3137 $d->{maxmem
} = $info->{max_mem
};
3138 $d->{balloon
} = $info->{actual
};
3140 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
3141 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
3142 $d->{freemem
} = $info->{free_mem
};
3145 $d->{ballooninfo
} = $info;
3148 my $blockstatscb = sub {
3149 my ($vmid, $resp) = @_;
3150 my $data = $resp->{'return'} || [];
3151 my $totalrdbytes = 0;
3152 my $totalwrbytes = 0;
3154 for my $blockstat (@$data) {
3155 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
3156 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
3158 $blockstat->{device
} =~ s/drive-//;
3159 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
3161 $res->{$vmid}->{diskread
} = $totalrdbytes;
3162 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
3165 my $statuscb = sub {
3166 my ($vmid, $resp) = @_;
3168 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
3169 # this fails if ballon driver is not loaded, so this must be
3170 # the last commnand (following command are aborted if this fails).
3171 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
3173 my $status = 'unknown';
3174 if (!defined($status = $resp->{'return'}->{status
})) {
3175 warn "unable to get VM status\n";
3179 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
3182 foreach my $vmid (keys %$list) {
3183 next if $opt_vmid && ($vmid ne $opt_vmid);
3184 next if !$res->{$vmid}->{pid
}; # not running
3185 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
3188 $qmpclient->queue_execute(undef, 2);
3190 foreach my $vmid (keys %$list) {
3191 next if $opt_vmid && ($vmid ne $opt_vmid);
3192 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
3199 my ($conf, $func, @param) = @_;
3201 foreach my $ds (valid_drive_names
()) {
3202 next if !defined($conf->{$ds});
3204 my $drive = parse_drive
($ds, $conf->{$ds});
3207 &$func($ds, $drive, @param);
3212 my ($conf, $func, @param) = @_;
3216 my $test_volid = sub {
3217 my ($volid, $is_cdrom, $replicate, $shared, $snapname) = @_;
3221 $volhash->{$volid}->{cdrom
} //= 1;
3222 $volhash->{$volid}->{cdrom
} = 0 if !$is_cdrom;
3224 $volhash->{$volid}->{replicate
} //= 0;
3225 $volhash->{$volid}->{replicate
} = 1 if $replicate;
3227 $volhash->{$volid}->{shared
} //= 0;
3228 $volhash->{$volid}->{shared
} = 1 if $shared;
3230 $volhash->{$volid}->{referenced_in_config
} //= 0;
3231 $volhash->{$volid}->{referenced_in_config
} = 1 if !defined($snapname);
3233 $volhash->{$volid}->{referenced_in_snapshot
}->{$snapname} = 1
3234 if defined($snapname);
3237 foreach_drive
($conf, sub {
3238 my ($ds, $drive) = @_;
3239 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, undef);
3242 foreach my $snapname (keys %{$conf->{snapshots
}}) {
3243 my $snap = $conf->{snapshots
}->{$snapname};
3244 $test_volid->($snap->{vmstate
}, 0, 1, $snapname);
3245 foreach_drive
($snap, sub {
3246 my ($ds, $drive) = @_;
3247 $test_volid->($drive->{file
}, drive_is_cdrom
($drive), $drive->{replicate
} // 1, $drive->{shared
}, $snapname);
3251 foreach my $volid (keys %$volhash) {
3252 &$func($volid, $volhash->{$volid}, @param);
3256 sub conf_has_serial
{
3259 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3260 if ($conf->{"serial$i"}) {
3268 sub vga_conf_has_spice
{
3271 my $vgaconf = parse_vga
($vga);
3272 my $vgatype = $vgaconf->{type
};
3273 return 0 if !$vgatype || $vgatype !~ m/^qxl([234])?$/;
3278 my $host_arch; # FIXME: fix PVE::Tools::get_host_arch
3279 sub get_host_arch
() {
3280 $host_arch = (POSIX
::uname
())[4] if !$host_arch;
3286 return get_host_arch
() eq $arch;
3289 my $default_machines = {
3294 sub get_basic_machine_info
{
3295 my ($conf, $forcemachine) = @_;
3297 my $arch = $conf->{arch
} // get_host_arch
();
3298 my $machine = $forcemachine || $conf->{machine
} || $default_machines->{$arch};
3299 return ($arch, $machine);
3302 sub get_ovmf_files
($) {
3305 my $ovmf = $OVMF->{$arch}
3306 or die "no OVMF images known for architecture '$arch'\n";
3312 aarch64
=> '/usr/bin/qemu-system-aarch64',
3313 x86_64
=> '/usr/bin/qemu-system-x86_64',
3315 sub get_command_for_arch
($) {
3317 return '/usr/bin/kvm' if is_native
($arch);
3319 my $cmd = $Arch2Qemu->{$arch}
3320 or die "don't know how to emulate architecture '$arch'\n";
3324 sub get_cpu_options
{
3325 my ($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough) = @_;
3328 my $ostype = $conf->{ostype
};
3330 my $cpu = $kvm ?
"kvm64" : "qemu64";
3331 if ($arch eq 'aarch64') {
3332 $cpu = 'cortex-a57';
3334 if (my $cputype = $conf->{cpu
}) {
3335 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
3336 or die "Cannot parse cpu description: $cputype\n";
3337 $cpu = $cpuconf->{cputype
};
3338 $kvm_off = 1 if $cpuconf->{hidden
};
3340 if (defined(my $flags = $cpuconf->{flags
})) {
3341 push @$cpuFlags, split(";", $flags);
3345 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64' && $arch eq 'x86_64';
3347 push @$cpuFlags , '-x2apic'
3348 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3350 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3352 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3354 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3) && $arch eq 'x86_64') {
3356 push @$cpuFlags , '+kvm_pv_unhalt' if $kvm;
3357 push @$cpuFlags , '+kvm_pv_eoi' if $kvm;
3360 add_hyperv_enlightenments
($cpuFlags, $winversion, $machine_type, $kvmver, $conf->{bios
}, $gpu_passthrough) if $kvm;
3362 push @$cpuFlags, 'enforce' if $cpu ne 'host' && $kvm && $arch eq 'x86_64';
3364 push @$cpuFlags, 'kvm=off' if $kvm_off;
3366 if (my $cpu_vendor = $cpu_vendor_list->{$cpu}) {
3367 push @$cpuFlags, "vendor=${cpu_vendor}"
3368 if $cpu_vendor ne 'default';
3369 } elsif ($arch ne 'aarch64') {
3370 die "internal error"; # should not happen
3373 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3375 return ('-cpu', $cpu);
3378 sub config_to_command
{
3379 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
3382 my $globalFlags = [];
3383 my $machineFlags = [];
3388 my $kvmver = kvm_user_version
();
3389 my $vernum = 0; # unknown
3390 my $ostype = $conf->{ostype
};
3391 my $winversion = windows_version
($ostype);
3392 my $kvm = $conf->{kvm
};
3394 my ($arch, $machine_type) = get_basic_machine_info
($conf, $forcemachine);
3395 $kvm //= 1 if is_native
($arch);
3398 die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n"
3399 if !defined kvm_version
();
3402 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
3403 $vernum = $1*1000000+$2*1000;
3404 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
3405 $vernum = $1*1000000+$2*1000+$3;
3408 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
3410 my $have_ovz = -f
'/proc/vz/vestat';
3412 my $q35 = machine_type_is_q35
($conf);
3413 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
3414 my $use_old_bios_files = undef;
3415 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3417 my $cpuunits = defined($conf->{cpuunits
}) ?
3418 $conf->{cpuunits
} : $defaults->{cpuunits
};
3420 push @$cmd, get_command_for_arch
($arch);
3422 push @$cmd, '-id', $vmid;
3424 my $vmname = $conf->{name
} || "vm$vmid";
3426 push @$cmd, '-name', $vmname;
3430 my $qmpsocket = qmp_socket
($vmid);
3431 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
3432 push @$cmd, '-mon', "chardev=qmp,mode=control";
3434 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
3435 push @$cmd, '-chardev', "socket,id=qmp-event,path=/var/run/qmeventd.sock,reconnect=5";
3436 push @$cmd, '-mon', "chardev=qmp-event,mode=control";
3439 push @$cmd, '-pidfile' , pidfile_name
($vmid);
3441 push @$cmd, '-daemonize';
3443 if ($conf->{smbios1
}) {
3444 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
3447 if ($conf->{vmgenid
}) {
3448 push @$devices, '-device', 'vmgenid,guid='.$conf->{vmgenid
};
3451 my ($ovmf_code, $ovmf_vars) = get_ovmf_files
($arch);
3452 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3453 die "uefi base image not found\n" if ! -f
$ovmf_code;
3457 if (my $efidisk = $conf->{efidisk0
}) {
3458 my $d = PVE
::JSONSchema
::parse_property_string
($efidisk_fmt, $efidisk);
3459 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
3460 $format = $d->{format
};
3462 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
3463 if (!defined($format)) {
3464 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
3465 $format = qemu_img_format
($scfg, $volname);
3469 die "efidisk format must be specified\n"
3470 if !defined($format);
3473 warn "no efidisk configured! Using temporary efivars disk.\n";
3474 $path = "/tmp/$vmid-ovmf.fd";
3475 PVE
::Tools
::file_copy
($ovmf_vars, $path, -s
$ovmf_vars);
3479 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$ovmf_code";
3480 push @$cmd, '-drive', "if=pflash,unit=1,format=$format,id=drive-efidisk0,file=$path";
3484 # add usb controllers
3485 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $arch, $machine_type, $usbdesc->{format
}, $MAX_USB_DEVICES);
3486 push @$devices, @usbcontrollers if @usbcontrollers;
3487 my $vga = parse_vga
($conf->{vga
});
3489 my $qxlnum = vga_conf_has_spice
($conf->{vga
});
3490 $vga->{type
} = 'qxl' if $qxlnum;
3492 if (!$vga->{type
}) {
3493 if ($arch eq 'aarch64') {
3494 $vga->{type
} = 'virtio';
3495 } elsif (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 9)) {
3496 $vga->{type
} = (!$winversion || $winversion >= 6) ?
'std' : 'cirrus';
3498 $vga->{type
} = ($winversion >= 6) ?
'std' : 'cirrus';
3502 # enable absolute mouse coordinates (needed by vnc)
3504 if (defined($conf->{tablet
})) {
3505 $tablet = $conf->{tablet
};
3507 $tablet = $defaults->{tablet
};
3508 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
3509 $tablet = 0 if $vga->{type
} =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
3513 push @$devices, '-device', print_tabletdevice_full
($conf, $arch) if $tablet;
3514 my $kbd = print_keyboarddevice_full
($conf, $arch);
3515 push @$devices, '-device', $kbd if defined($kbd);
3519 my $gpu_passthrough;
3522 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
3523 my $d = parse_hostpci
($conf->{"hostpci$i"});
3526 my $pcie = $d->{pcie
};
3528 die "q35 machine model is not enabled" if !$q35;
3529 # win7 wants to have the pcie devices directly on the pcie bus
3530 # instead of in the root port
3531 if ($winversion == 7) {
3532 $pciaddr = print_pcie_addr
("hostpci${i}bus0");
3534 $pciaddr = print_pcie_addr
("hostpci$i");
3537 $pciaddr = print_pci_addr
("hostpci$i", $bridges, $arch, $machine_type);
3540 my $rombar = defined($d->{rombar
}) && !$d->{rombar
} ?
',rombar=0' : '';
3541 my $romfile = $d->{romfile
};
3544 if ($d->{'x-vga'}) {
3545 $xvga = ',x-vga=on';
3547 $vga->{type
} = 'none';
3548 $gpu_passthrough = 1;
3550 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
3554 my $pcidevices = $d->{pciid
};
3555 my $multifunction = 1 if @$pcidevices > 1;
3557 if ($d->{mdev
} && scalar(@$pcidevices) == 1) {
3558 my $id = $pcidevices->[0]->{id
};
3559 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $i);
3560 $sysfspath = "/sys/bus/pci/devices/0000:$id/$uuid";
3561 } elsif ($d->{mdev
}) {
3562 warn "ignoring mediated device with multifunction device\n";
3566 foreach my $pcidevice (@$pcidevices) {
3568 my $id = "hostpci$i";
3569 $id .= ".$j" if $multifunction;
3570 my $addr = $pciaddr;
3571 $addr .= ".$j" if $multifunction;
3572 my $devicestr = "vfio-pci";
3574 $devicestr .= ",sysfsdev=$sysfspath";
3576 $devicestr .= ",host=$pcidevice->{id}";
3578 $devicestr .= ",id=$id$addr";
3581 $devicestr .= "$rombar$xvga";
3582 $devicestr .= ",multifunction=on" if $multifunction;
3583 $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
3586 push @$devices, '-device', $devicestr;
3592 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES);
3593 push @$devices, @usbdevices if @usbdevices;
3595 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
3596 if (my $path = $conf->{"serial$i"}) {
3597 if ($path eq 'socket') {
3598 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
3599 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
3600 # On aarch64, serial0 is the UART device. Qemu only allows
3601 # connecting UART devices via the '-serial' command line, as
3602 # the device has a fixed slot on the hardware...
3603 if ($arch eq 'aarch64' && $i == 0) {
3604 push @$devices, '-serial', "chardev:serial$i";
3606 push @$devices, '-device', "isa-serial,chardev=serial$i";
3609 die "no such serial device\n" if ! -c
$path;
3610 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
3611 push @$devices, '-device', "isa-serial,chardev=serial$i";
3617 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
3618 if (my $path = $conf->{"parallel$i"}) {
3619 die "no such parallel device\n" if ! -c
$path;
3620 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
3621 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
3622 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
3628 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
3629 $sockets = $conf->{sockets
} if $conf->{sockets
};
3631 my $cores = $conf->{cores
} || 1;
3633 my $maxcpus = $sockets * $cores;
3635 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
3637 my $allowed_vcpus = $cpuinfo->{cpus
};
3639 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
3640 if ($allowed_vcpus < $maxcpus);
3642 if($hotplug_features->{cpu
} && qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 7)) {
3644 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3645 for (my $i = 2; $i <= $vcpus; $i++) {
3646 my $cpustr = print_cpu_device
($conf,$i);
3647 push @$cmd, '-device', $cpustr;
3652 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3654 push @$cmd, '-nodefaults';
3656 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3658 my $bootindex_hash = {};
3660 foreach my $o (split(//, $bootorder)) {
3661 $bootindex_hash->{$o} = $i*100;
3665 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3667 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3669 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3671 if ($vga->{type
} && $vga->{type
} !~ m/^serial\d+$/ && $vga->{type
} ne 'none'){
3672 push @$devices, '-device', print_vga_device
($conf, $vga, $arch, $machine_type, undef, $qxlnum, $bridges);
3673 my $socket = vnc_socket
($vmid);
3674 push @$cmd, '-vnc', "unix:$socket,x509,password";
3676 push @$cmd, '-vga', 'none' if $vga->{type
} eq 'none';
3677 push @$cmd, '-nographic';
3681 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3683 my $useLocaltime = $conf->{localtime};
3685 if ($winversion >= 5) { # windows
3686 $useLocaltime = 1 if !defined($conf->{localtime});
3688 # use time drift fix when acpi is enabled
3689 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3690 $tdf = 1 if !defined($conf->{tdf
});
3694 if ($winversion >= 6) {
3695 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3696 push @$cmd, '-no-hpet';
3699 push @$rtcFlags, 'driftfix=slew' if $tdf;
3702 push @$machineFlags, 'accel=tcg';
3705 if ($machine_type) {
3706 push @$machineFlags, "type=${machine_type}";
3709 if ($conf->{startdate
}) {
3710 push @$rtcFlags, "base=$conf->{startdate}";
3711 } elsif ($useLocaltime) {
3712 push @$rtcFlags, 'base=localtime';
3715 push @$cmd, get_cpu_options
($conf, $arch, $kvm, $machine_type, $kvm_off, $kvmver, $winversion, $gpu_passthrough);
3717 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3719 push @$cmd, '-S' if $conf->{freeze
};
3721 push @$cmd, '-k', $conf->{keyboard
} if defined($conf->{keyboard
});
3724 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3725 #push @$cmd, '-soundhw', 'es1370';
3726 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3728 if (parse_guest_agent
($conf)->{enabled
}) {
3729 my $qgasocket = qmp_socket
($vmid, 1);
3730 my $pciaddr = print_pci_addr
("qga0", $bridges, $arch, $machine_type);
3731 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3732 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3733 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3741 for(my $i = 1; $i < $qxlnum; $i++){
3742 push @$devices, '-device', print_vga_device
($conf, $vga, $arch, $machine_type, $i, $qxlnum, $bridges);
3745 # assume other OS works like Linux
3746 my ($ram, $vram) = ("134217728", "67108864");
3747 if ($vga->{memory
}) {
3748 $ram = PVE
::Tools
::convert_size
($qxlnum*4*$vga->{memory
}, 'mb' => 'b');
3749 $vram = PVE
::Tools
::convert_size
($qxlnum*2*$vga->{memory
}, 'mb' => 'b');
3751 push @$cmd, '-global', "qxl-vga.ram_size=$ram";
3752 push @$cmd, '-global', "qxl-vga.vram_size=$vram";
3756 my $pciaddr = print_pci_addr
("spice", $bridges, $arch, $machine_type);
3758 my $nodename = PVE
::INotify
::nodename
();
3759 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3760 my @nodeaddrs = PVE
::Tools
::getaddrinfo_all
('localhost', family
=> $pfamily);
3761 die "failed to get an ip address of type $pfamily for 'localhost'\n" if !@nodeaddrs;
3762 my $localhost = PVE
::Network
::addr_to_ip
($nodeaddrs[0]->{addr
});
3763 $spice_port = PVE
::Tools
::next_spice_port
($pfamily, $localhost);
3765 push @$devices, '-spice', "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
3767 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3768 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3769 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3772 # enable balloon by default, unless explicitly disabled
3773 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3774 $pciaddr = print_pci_addr
("balloon0", $bridges, $arch, $machine_type);
3775 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3778 if ($conf->{watchdog
}) {
3779 my $wdopts = parse_watchdog
($conf->{watchdog
});
3780 $pciaddr = print_pci_addr
("watchdog", $bridges, $arch, $machine_type);
3781 my $watchdog = $wdopts->{model
} || 'i6300esb';
3782 push @$devices, '-device', "$watchdog$pciaddr";
3783 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3787 my $scsicontroller = {};
3788 my $ahcicontroller = {};
3789 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3791 # Add iscsi initiator name if available
3792 if (my $initiator = get_initiator_name
()) {
3793 push @$devices, '-iscsi', "initiator-name=$initiator";
3796 foreach_drive
($conf, sub {
3797 my ($ds, $drive) = @_;
3799 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3800 push @$vollist, $drive->{file
};
3803 # ignore efidisk here, already added in bios/fw handling code above
3804 return if $drive->{interface
} eq 'efidisk';
3806 $use_virtio = 1 if $ds =~ m/^virtio/;
3808 if (drive_is_cdrom
($drive)) {
3809 if ($bootindex_hash->{d
}) {
3810 $drive->{bootindex
} = $bootindex_hash->{d
};
3811 $bootindex_hash->{d
} += 1;
3814 if ($bootindex_hash->{c
}) {
3815 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3816 $bootindex_hash->{c
} += 1;
3820 if($drive->{interface
} eq 'virtio'){
3821 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3824 if ($drive->{interface
} eq 'scsi') {
3826 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3828 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges, $arch, $machine_type);
3829 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3832 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3833 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3834 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3835 } elsif ($drive->{iothread
}) {
3836 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3840 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3841 $queues = ",num_queues=$drive->{queues}";
3844 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3845 $scsicontroller->{$controller}=1;
3848 if ($drive->{interface
} eq 'sata') {
3849 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3850 $pciaddr = print_pci_addr
("ahci$controller", $bridges, $arch, $machine_type);
3851 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3852 $ahcicontroller->{$controller}=1;
3855 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3856 push @$devices, '-drive',$drive_cmd;
3857 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type);
3860 for (my $i = 0; $i < $MAX_NETS; $i++) {
3861 next if !$conf->{"net$i"};
3862 my $d = parse_net
($conf->{"net$i"});
3865 $use_virtio = 1 if $d->{model
} eq 'virtio';
3867 if ($bootindex_hash->{n
}) {
3868 $d->{bootindex
} = $bootindex_hash->{n
};
3869 $bootindex_hash->{n
} += 1;
3872 my $netdevfull = print_netdev_full
($vmid, $conf, $arch, $d, "net$i");
3873 push @$devices, '-netdev', $netdevfull;
3875 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files, $arch, $machine_type);
3876 push @$devices, '-device', $netdevicefull;
3881 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3886 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3888 while (my ($k, $v) = each %$bridges) {
3889 $pciaddr = print_pci_addr
("pci.$k", undef, $arch, $machine_type);
3890 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3894 push @$cmd, @$devices;
3895 push @$cmd, '-rtc', join(',', @$rtcFlags)
3896 if scalar(@$rtcFlags);
3897 push @$cmd, '-machine', join(',', @$machineFlags)
3898 if scalar(@$machineFlags);
3899 push @$cmd, '-global', join(',', @$globalFlags)
3900 if scalar(@$globalFlags);
3903 if ($conf->{args
}) {
3904 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3908 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3913 return "${var_run_tmpdir}/$vmid.vnc";
3919 my $res = vm_mon_cmd
($vmid, 'query-spice');
3921 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3925 my ($vmid, $qga, $name) = @_;
3926 my $sockettype = $qga ?
'qga' : 'qmp';
3927 my $ext = $name ?
'-'.$name : '';
3928 return "${var_run_tmpdir}/$vmid$ext.$sockettype";
3933 return "${var_run_tmpdir}/$vmid.pid";
3936 sub vm_devices_list
{
3939 my $res = vm_mon_cmd
($vmid, 'query-pci');
3940 my $devices_to_check = [];
3942 foreach my $pcibus (@$res) {
3943 push @$devices_to_check, @{$pcibus->{devices
}},
3946 while (@$devices_to_check) {
3948 for my $d (@$devices_to_check) {
3949 $devices->{$d->{'qdev_id'}} = 1 if $d->{'qdev_id'};
3950 next if !$d->{'pci_bridge'};
3952 $devices->{$d->{'qdev_id'}} += scalar(@{$d->{'pci_bridge'}->{devices
}});
3953 push @$to_check, @{$d->{'pci_bridge'}->{devices
}};
3955 $devices_to_check = $to_check;
3958 my $resblock = vm_mon_cmd
($vmid, 'query-block');
3959 foreach my $block (@$resblock) {
3960 if($block->{device
} =~ m/^drive-(\S+)/){
3965 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
3966 foreach my $mice (@$resmice) {
3967 if ($mice->{name
} eq 'QEMU HID Tablet') {
3968 $devices->{tablet
} = 1;
3973 # for usb devices there is no query-usb
3974 # but we can iterate over the entries in
3975 # qom-list path=/machine/peripheral
3976 my $resperipheral = vm_mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3977 foreach my $per (@$resperipheral) {
3978 if ($per->{name
} =~ m/^usb\d+$/) {
3979 $devices->{$per->{name
}} = 1;
3987 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
3989 my $q35 = machine_type_is_q35
($conf);
3991 my $devices_list = vm_devices_list
($vmid);
3992 return 1 if defined($devices_list->{$deviceid});
3994 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type); # add PCI bridge if we need it for the device
3996 if ($deviceid eq 'tablet') {
3998 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf, $arch));
4000 } elsif ($deviceid eq 'keyboard') {
4002 qemu_deviceadd
($vmid, print_keyboarddevice_full
($conf, $arch));
4004 } elsif ($deviceid =~ m/^usb(\d+)$/) {
4006 die "usb hotplug currently not reliable\n";
4007 # since we can't reliably hot unplug all added usb devices
4008 # and usb passthrough disables live migration
4009 # we disable usb hotplugging for now
4010 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
4012 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4014 qemu_iothread_add
($vmid, $deviceid, $device);
4016 qemu_driveadd
($storecfg, $vmid, $device);
4017 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, $arch, $machine_type);
4019 qemu_deviceadd
($vmid, $devicefull);
4020 eval { qemu_deviceaddverify
($vmid, $deviceid); };
4022 eval { qemu_drivedel
($vmid, $deviceid); };
4027 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4030 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
4031 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4032 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
4034 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
4036 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
4037 qemu_iothread_add
($vmid, $deviceid, $device);
4038 $devicefull .= ",iothread=iothread-$deviceid";
4041 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
4042 $devicefull .= ",num_queues=$device->{queues}";
4045 qemu_deviceadd
($vmid, $devicefull);
4046 qemu_deviceaddverify
($vmid, $deviceid);
4048 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4050 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device, $arch, $machine_type);
4051 qemu_driveadd
($storecfg, $vmid, $device);
4053 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device, $arch, $machine_type);
4054 eval { qemu_deviceadd
($vmid, $devicefull); };
4056 eval { qemu_drivedel
($vmid, $deviceid); };
4061 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4063 return undef if !qemu_netdevadd
($vmid, $conf, $arch, $device, $deviceid);
4065 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
4066 my $use_old_bios_files = undef;
4067 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
4069 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
4070 qemu_deviceadd
($vmid, $netdevicefull);
4071 eval { qemu_deviceaddverify
($vmid, $deviceid); };
4073 eval { qemu_netdevdel
($vmid, $deviceid); };
4078 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
4081 my $pciaddr = print_pci_addr
($deviceid, undef, $arch, $machine_type);
4082 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
4084 qemu_deviceadd
($vmid, $devicefull);
4085 qemu_deviceaddverify
($vmid, $deviceid);
4088 die "can't hotplug device '$deviceid'\n";
4094 # fixme: this should raise exceptions on error!
4095 sub vm_deviceunplug
{
4096 my ($vmid, $conf, $deviceid) = @_;
4098 my $devices_list = vm_devices_list
($vmid);
4099 return 1 if !defined($devices_list->{$deviceid});
4101 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
4103 if ($deviceid eq 'tablet' || $deviceid eq 'keyboard') {
4105 qemu_devicedel
($vmid, $deviceid);
4107 } elsif ($deviceid =~ m/^usb\d+$/) {
4109 die "usb hotplug currently not reliable\n";
4110 # when unplugging usb devices this way,
4111 # there may be remaining usb controllers/hubs
4112 # so we disable it for now
4113 qemu_devicedel
($vmid, $deviceid);
4114 qemu_devicedelverify
($vmid, $deviceid);
4116 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
4118 qemu_devicedel
($vmid, $deviceid);
4119 qemu_devicedelverify
($vmid, $deviceid);
4120 qemu_drivedel
($vmid, $deviceid);
4121 qemu_iothread_del
($conf, $vmid, $deviceid);
4123 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
4125 qemu_devicedel
($vmid, $deviceid);
4126 qemu_devicedelverify
($vmid, $deviceid);
4127 qemu_iothread_del
($conf, $vmid, $deviceid);
4129 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
4131 qemu_devicedel
($vmid, $deviceid);
4132 qemu_drivedel
($vmid, $deviceid);
4133 qemu_deletescsihw
($conf, $vmid, $deviceid);
4135 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
4137 qemu_devicedel
($vmid, $deviceid);
4138 qemu_devicedelverify
($vmid, $deviceid);
4139 qemu_netdevdel
($vmid, $deviceid);
4142 die "can't unplug device '$deviceid'\n";
4148 sub qemu_deviceadd
{
4149 my ($vmid, $devicefull) = @_;
4151 $devicefull = "driver=".$devicefull;
4152 my %options = split(/[=,]/, $devicefull);
4154 vm_mon_cmd
($vmid, "device_add" , %options);
4157 sub qemu_devicedel
{
4158 my ($vmid, $deviceid) = @_;
4160 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
4163 sub qemu_iothread_add
{
4164 my($vmid, $deviceid, $device) = @_;
4166 if ($device->{iothread
}) {
4167 my $iothreads = vm_iothreads_list
($vmid);
4168 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
4172 sub qemu_iothread_del
{
4173 my($conf, $vmid, $deviceid) = @_;
4175 my $device = parse_drive
($deviceid, $conf->{$deviceid});
4176 if ($device->{iothread
}) {
4177 my $iothreads = vm_iothreads_list
($vmid);
4178 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
4182 sub qemu_objectadd
{
4183 my($vmid, $objectid, $qomtype) = @_;
4185 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
4190 sub qemu_objectdel
{
4191 my($vmid, $objectid) = @_;
4193 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
4199 my ($storecfg, $vmid, $device) = @_;
4201 my $drive = print_drive_full
($storecfg, $vmid, $device);
4202 $drive =~ s/\\/\\\\/g;
4203 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
4205 # If the command succeeds qemu prints: "OK
"
4206 return 1 if $ret =~ m/OK/s;
4208 die "adding drive failed
: $ret\n";
4212 my($vmid, $deviceid) = @_;
4214 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
4217 return 1 if $ret eq "";
4219 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
4220 return 1 if $ret =~ m/Device \'.*?\' not found/s;
4222 die "deleting drive
$deviceid failed
: $ret\n";
4225 sub qemu_deviceaddverify {
4226 my ($vmid, $deviceid) = @_;
4228 for (my $i = 0; $i <= 5; $i++) {
4229 my $devices_list = vm_devices_list($vmid);
4230 return 1 if defined($devices_list->{$deviceid});
4234 die "error on hotplug device
'$deviceid'\n";
4238 sub qemu_devicedelverify {
4239 my ($vmid, $deviceid) = @_;
4241 # need to verify that the device is correctly removed as device_del
4242 # is async and empty return is not reliable
4244 for (my $i = 0; $i <= 5; $i++) {
4245 my $devices_list = vm_devices_list($vmid);
4246 return 1 if !defined($devices_list->{$deviceid});
4250 die "error on hot-unplugging device
'$deviceid'\n";
4253 sub qemu_findorcreatescsihw {
4254 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4256 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4258 my $scsihwid="$controller_prefix$controller";
4259 my $devices_list = vm_devices_list($vmid);
4261 if(!defined($devices_list->{$scsihwid})) {
4262 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $machine_type);
4268 sub qemu_deletescsihw {
4269 my ($conf, $vmid, $opt) = @_;
4271 my $device = parse_drive($opt, $conf->{$opt});
4273 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
4274 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
4278 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
4280 my $devices_list = vm_devices_list($vmid);
4281 foreach my $opt (keys %{$devices_list}) {
4282 if (PVE::QemuServer::is_valid_drivename($opt)) {
4283 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
4284 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
4290 my $scsihwid="scsihw
$controller";
4292 vm_deviceunplug($vmid, $conf, $scsihwid);
4297 sub qemu_add_pci_bridge {
4298 my ($storecfg, $conf, $vmid, $device, $arch, $machine_type) = @_;
4304 print_pci_addr($device, $bridges, $arch, $machine_type);
4306 while (my ($k, $v) = each %$bridges) {
4309 return 1 if !defined($bridgeid) || $bridgeid < 1;
4311 my $bridge = "pci
.$bridgeid";
4312 my $devices_list = vm_devices_list($vmid);
4314 if (!defined($devices_list->{$bridge})) {
4315 vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $machine_type);
4321 sub qemu_set_link_status {
4322 my ($vmid, $device, $up) = @_;
4324 vm_mon_cmd($vmid, "set_link
", name => $device,
4325 up => $up ? JSON::true : JSON::false);
4328 sub qemu_netdevadd {
4329 my ($vmid, $conf, $arch, $device, $deviceid) = @_;
4331 my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
4332 my %options = split(/[=,]/, $netdev);
4334 vm_mon_cmd($vmid, "netdev_add
", %options);
4338 sub qemu_netdevdel {
4339 my ($vmid, $deviceid) = @_;
4341 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
4344 sub qemu_usb_hotplug {
4345 my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $machine_type) = @_;
4349 # remove the old one first
4350 vm_deviceunplug($vmid, $conf, $deviceid);
4352 # check if xhci controller is necessary and available
4353 if ($device->{usb3}) {
4355 my $devicelist = vm_devices_list($vmid);
4357 if (!$devicelist->{xhci}) {
4358 my $pciaddr = print_pci_addr("xhci
", undef, $arch, $machine_type);
4359 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
4362 my $d = parse_usb_device($device->{host});
4363 $d->{usb3} = $device->{usb3};
4366 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d, $arch, $machine_type);
4369 sub qemu_cpu_hotplug {
4370 my ($vmid, $conf, $vcpus) = @_;
4372 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
4375 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
4376 $sockets = $conf->{sockets} if $conf->{sockets};
4377 my $cores = $conf->{cores} || 1;
4378 my $maxcpus = $sockets * $cores;
4380 $vcpus = $maxcpus if !$vcpus;
4382 die "you can
't add more vcpus than maxcpus\n"
4383 if $vcpus > $maxcpus;
4385 my $currentvcpus = $conf->{vcpus} || $maxcpus;
4387 if ($vcpus < $currentvcpus) {
4389 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4391 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
4392 qemu_devicedel($vmid, "cpu$i");
4394 my $currentrunningvcpus = undef;
4396 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4397 last if scalar(@{$currentrunningvcpus}) == $i-1;
4398 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
4402 #update conf after each succesfull cpu unplug
4403 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4404 PVE::QemuConfig->write_config($vmid, $conf);
4407 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
4413 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4414 die "vcpus in running vm does not match its configuration\n"
4415 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
4417 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
4419 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
4420 my $cpustr = print_cpu_device($conf, $i);
4421 qemu_deviceadd($vmid, $cpustr);
4424 my $currentrunningvcpus = undef;
4426 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
4427 last if scalar(@{$currentrunningvcpus}) == $i;
4428 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
4432 #update conf after each succesfull cpu hotplug
4433 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
4434 PVE::QemuConfig->write_config($vmid, $conf);
4438 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
4439 vm_mon_cmd($vmid, "cpu-add", id => int($i));
4444 sub qemu_block_set_io_throttle {
4445 my ($vmid, $deviceid,
4446 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
4447 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
4448 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
4449 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
4451 return if !check_running($vmid) ;
4453 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
4455 bps_rd => int($bps_rd),
4456 bps_wr => int($bps_wr),
4458 iops_rd => int($iops_rd),
4459 iops_wr => int($iops_wr),
4460 bps_max => int($bps_max),
4461 bps_rd_max => int($bps_rd_max),
4462 bps_wr_max => int($bps_wr_max),
4463 iops_max => int($iops_max),
4464 iops_rd_max => int($iops_rd_max),
4465 iops_wr_max => int($iops_wr_max),
4466 bps_max_length => int($bps_max_length),
4467 bps_rd_max_length => int($bps_rd_max_length),
4468 bps_wr_max_length => int($bps_wr_max_length),
4469 iops_max_length => int($iops_max_length),
4470 iops_rd_max_length => int($iops_rd_max_length),
4471 iops_wr_max_length => int($iops_wr_max_length),
4476 # old code, only used to shutdown old VM after update
4478 my ($fh, $timeout) = @_;
4480 my $sel = new IO::Select;
4487 while (scalar (@ready = $sel->can_read($timeout))) {
4489 if ($count = $fh->sysread($buf, 8192)) {
4490 if ($buf =~ /^(.*)\(qemu\) $/s) {
4497 if (!defined($count)) {
4504 die "monitor read timeout\n" if !scalar(@ready);
4509 sub qemu_block_resize {
4510 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
4512 my $running = check_running($vmid);
4514 $size = 0 if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
4516 return if !$running;
4518 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
4522 sub qemu_volume_snapshot {
4523 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4525 my $running = check_running($vmid);
4527 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4528 vm_mon_cmd($vmid, 'blockdev-snapshot-internal-sync
', device => $deviceid, name => $snap);
4530 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4534 sub qemu_volume_snapshot_delete {
4535 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4537 my $running = check_running($vmid);
4542 my $conf = PVE::QemuConfig->load_config($vmid);
4543 foreach_drive($conf, sub {
4544 my ($ds, $drive) = @_;
4545 $running = 1 if $drive->{file} eq $volid;
4549 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4550 vm_mon_cmd($vmid, 'blockdev-snapshot-delete-internal-sync
', device => $deviceid, name => $snap);
4552 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4556 sub set_migration_caps {
4562 "auto-converge" => 1,
4564 "x-rdma-pin-all" => 0,
4569 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4571 for my $supported_capability (@$supported_capabilities) {
4573 capability => $supported_capability->{capability},
4574 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4578 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4581 my $fast_plug_option = {
4589 'vmstatestorage
' => 1,
4592 # hotplug changes in [PENDING]
4593 # $selection hash can be used to only apply specified options, for
4594 # example: { cores => 1 } (only apply changed 'cores
')
4595 # $errors ref is used to return error messages
4596 sub vmconfig_hotplug_pending {
4597 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4599 my $defaults = load_defaults();
4600 my ($arch, $machine_type) = get_basic_machine_info($conf, undef);
4602 # commit values which do not have any impact on running VM first
4603 # Note: those option cannot raise errors, we we do not care about
4604 # $selection and always apply them.
4606 my $add_error = sub {
4607 my ($opt, $msg) = @_;
4608 $errors->{$opt} = "hotplug problem - $msg";
4612 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4613 if ($fast_plug_option->{$opt}) {
4614 $conf->{$opt} = $conf->{pending}->{$opt};
4615 delete $conf->{pending}->{$opt};
4621 PVE::QemuConfig->write_config($vmid, $conf);
4622 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4625 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4627 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4628 while (my ($opt, $force) = each %$pending_delete_hash) {
4629 next if $selection && !$selection->{$opt};
4631 if ($opt eq 'hotplug
') {
4632 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4633 } elsif ($opt eq 'tablet
') {
4634 die "skip\n" if !$hotplug_features->{usb};
4635 if ($defaults->{tablet}) {
4636 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4637 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4638 if $arch eq 'aarch64
';
4640 vm_deviceunplug($vmid, $conf, 'tablet
');
4641 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4643 } elsif ($opt =~ m/^usb\d+/) {
4645 # since we cannot reliably hot unplug usb devices
4646 # we are disabling it
4647 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4648 vm_deviceunplug($vmid, $conf, $opt);
4649 } elsif ($opt eq 'vcpus
') {
4650 die "skip\n" if !$hotplug_features->{cpu};
4651 qemu_cpu_hotplug($vmid, $conf, undef);
4652 } elsif ($opt eq 'balloon
') {
4653 # enable balloon device is not hotpluggable
4654 die "skip\n" if defined($conf->{balloon}) && $conf->{balloon} == 0;
4655 # here we reset the ballooning value to memory
4656 my $balloon = $conf->{memory} || $defaults->{memory};
4657 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4658 } elsif ($fast_plug_option->{$opt}) {
4660 } elsif ($opt =~ m/^net(\d+)$/) {
4661 die "skip\n" if !$hotplug_features->{network};
4662 vm_deviceunplug($vmid, $conf, $opt);
4663 } elsif (is_valid_drivename($opt)) {
4664 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4665 vm_deviceunplug($vmid, $conf, $opt);
4666 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4667 } elsif ($opt =~ m/^memory$/) {
4668 die "skip\n" if !$hotplug_features->{memory};
4669 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4670 } elsif ($opt eq 'cpuunits
') {
4671 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4672 } elsif ($opt eq 'cpulimit
') {
4673 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4679 &$add_error($opt, $err) if $err ne "skip\n";
4681 # save new config if hotplug was successful
4682 delete $conf->{$opt};
4683 vmconfig_undelete_pending_option($conf, $opt);
4684 PVE::QemuConfig->write_config($vmid, $conf);
4685 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4689 my $apply_pending_cloudinit;
4690 $apply_pending_cloudinit = sub {
4691 my ($key, $value) = @_;
4692 $apply_pending_cloudinit = sub {}; # once is enough
4694 my @cloudinit_opts = keys %$confdesc_cloudinit;
4695 foreach my $opt (keys %{$conf->{pending}}) {
4696 next if !grep { $_ eq $opt } @cloudinit_opts;
4697 $conf->{$opt} = delete $conf->{pending}->{$opt};
4700 my $new_conf = { %$conf };
4701 $new_conf->{$key} = $value;
4702 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($new_conf, $vmid);
4705 foreach my $opt (keys %{$conf->{pending}}) {
4706 next if $selection && !$selection->{$opt};
4707 my $value = $conf->{pending}->{$opt};
4709 if ($opt eq 'hotplug
') {
4710 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4711 } elsif ($opt eq 'tablet
') {
4712 die "skip\n" if !$hotplug_features->{usb};
4714 vm_deviceplug($storecfg, $conf, $vmid, 'tablet
', $arch, $machine_type);
4715 vm_deviceplug($storecfg, $conf, $vmid, 'keyboard
', $arch, $machine_type)
4716 if $arch eq 'aarch64
';
4717 } elsif ($value == 0) {
4718 vm_deviceunplug($vmid, $conf, 'tablet
');
4719 vm_deviceunplug($vmid, $conf, 'keyboard
') if $arch eq 'aarch64
';
4721 } elsif ($opt =~ m/^usb\d+$/) {
4723 # since we cannot reliably hot unplug usb devices
4724 # we are disabling it
4725 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4726 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4727 die "skip\n" if !$d;
4728 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $machine_type);
4729 } elsif ($opt eq 'vcpus
') {
4730 die "skip\n" if !$hotplug_features->{cpu};
4731 qemu_cpu_hotplug($vmid, $conf, $value);
4732 } elsif ($opt eq 'balloon
') {
4733 # enable/disable balloning device is not hotpluggable
4734 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4735 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4736 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4738 # allow manual ballooning if shares is set to zero
4739 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4740 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4741 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4743 } elsif ($opt =~ m/^net(\d+)$/) {
4744 # some changes can be done without hotplug
4745 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4746 $vmid, $opt, $value, $arch, $machine_type);
4747 } elsif (is_valid_drivename($opt)) {
4748 # some changes can be done without hotplug
4749 my $drive = parse_drive($opt, $value);
4750 if (drive_is_cloudinit($drive)) {
4751 &$apply_pending_cloudinit($opt, $value);
4753 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4754 $vmid, $opt, $value, 1, $arch, $machine_type);
4755 } elsif ($opt =~ m/^memory$/) { #dimms
4756 die "skip\n" if !$hotplug_features->{memory};
4757 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4758 } elsif ($opt eq 'cpuunits
') {
4759 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4760 } elsif ($opt eq 'cpulimit
') {
4761 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4762 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4764 die "skip\n"; # skip non-hot-pluggable options
4768 &$add_error($opt, $err) if $err ne "skip\n";
4770 # save new config if hotplug was successful
4771 $conf->{$opt} = $value;
4772 delete $conf->{pending}->{$opt};
4773 PVE::QemuConfig->write_config($vmid, $conf);
4774 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4779 sub try_deallocate_drive {
4780 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4782 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4783 my $volid = $drive->{file};
4784 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4785 my $sid = PVE::Storage::parse_volume_id($volid);
4786 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4788 # check if the disk is really unused
4789 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4790 if is_volume_in_use($storecfg, $conf, $key, $volid);
4791 PVE::Storage::vdisk_free($storecfg, $volid);
4794 # If vm is not owner of this disk remove from config
4802 sub vmconfig_delete_or_detach_drive {
4803 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4805 my $drive = parse_drive($opt, $conf->{$opt});
4807 my $rpcenv = PVE::RPCEnvironment::get();
4808 my $authuser = $rpcenv->get_user();
4811 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4812 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4814 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4818 sub vmconfig_apply_pending {
4819 my ($vmid, $conf, $storecfg) = @_;
4823 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4824 while (my ($opt, $force) = each %$pending_delete_hash) {
4825 die "internal error" if $opt =~ m/^unused/;
4826 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4827 if (!defined($conf->{$opt})) {
4828 vmconfig_undelete_pending_option($conf, $opt);
4829 PVE::QemuConfig->write_config($vmid, $conf);
4830 } elsif (is_valid_drivename($opt)) {
4831 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4832 vmconfig_undelete_pending_option($conf, $opt);
4833 delete $conf->{$opt};
4834 PVE::QemuConfig->write_config($vmid, $conf);
4836 vmconfig_undelete_pending_option($conf, $opt);
4837 delete $conf->{$opt};
4838 PVE::QemuConfig->write_config($vmid, $conf);
4842 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4844 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4845 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4847 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4848 # skip if nothing changed
4849 } elsif (is_valid_drivename($opt)) {
4850 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4851 if defined($conf->{$opt});
4852 $conf->{$opt} = $conf->{pending}->{$opt};
4854 $conf->{$opt} = $conf->{pending}->{$opt};
4857 delete $conf->{pending}->{$opt};
4858 PVE::QemuConfig->write_config($vmid, $conf);
4862 my $safe_num_ne = sub {
4865 return 0 if !defined($a) && !defined($b);
4866 return 1 if !defined($a);
4867 return 1 if !defined($b);
4872 my $safe_string_ne = sub {
4875 return 0 if !defined($a) && !defined($b);
4876 return 1 if !defined($a);
4877 return 1 if !defined($b);
4882 sub vmconfig_update_net {
4883 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $machine_type) = @_;
4885 my $newnet = parse_net($value);
4887 if ($conf->{$opt}) {
4888 my $oldnet = parse_net($conf->{$opt});
4890 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4891 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4892 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4893 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4895 # for non online change, we try to hot-unplug
4896 die "skip\n" if !$hotplug;
4897 vm_deviceunplug($vmid, $conf, $opt);
4900 die "internal error" if $opt !~ m/net(\d+)/;
4901 my $iface = "tap${vmid}i$1";
4903 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4904 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4905 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4906 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4907 PVE::Network::tap_unplug($iface);
4908 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4909 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4910 # Rate can be applied on its own but any change above needs to
4911 # include the rate in tap_plug since OVS resets everything.
4912 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4915 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4916 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4924 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $machine_type);
4930 sub vmconfig_update_disk {
4931 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force, $arch, $machine_type) = @_;
4933 # fixme: do we need force?
4935 my $drive = parse_drive($opt, $value);
4937 if ($conf->{$opt}) {
4939 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4941 my $media = $drive->{media} || 'disk
';
4942 my $oldmedia = $old_drive->{media} || 'disk
';
4943 die "unable to change media type\n" if $media ne $oldmedia;
4945 if (!drive_is_cdrom($old_drive)) {
4947 if ($drive->{file} ne $old_drive->{file}) {
4949 die "skip\n" if !$hotplug;
4951 # unplug and register as unused
4952 vm_deviceunplug($vmid, $conf, $opt);
4953 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4956 # update existing disk
4958 # skip non hotpluggable value
4959 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4960 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4961 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4962 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
4967 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4968 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4969 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4970 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4971 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4972 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4973 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4974 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4975 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4976 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4977 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4978 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4979 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4980 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4981 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4982 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4983 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4984 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4986 qemu_block_set_io_throttle($vmid,"drive-$opt",
4987 ($drive->{mbps} || 0)*1024*1024,
4988 ($drive->{mbps_rd} || 0)*1024*1024,
4989 ($drive->{mbps_wr} || 0)*1024*1024,
4990 $drive->{iops} || 0,
4991 $drive->{iops_rd} || 0,
4992 $drive->{iops_wr} || 0,
4993 ($drive->{mbps_max} || 0)*1024*1024,
4994 ($drive->{mbps_rd_max} || 0)*1024*1024,
4995 ($drive->{mbps_wr_max} || 0)*1024*1024,
4996 $drive->{iops_max} || 0,
4997 $drive->{iops_rd_max} || 0,
4998 $drive->{iops_wr_max} || 0,
4999 $drive->{bps_max_length} || 1,
5000 $drive->{bps_rd_max_length} || 1,
5001 $drive->{bps_wr_max_length} || 1,
5002 $drive->{iops_max_length} || 1,
5003 $drive->{iops_rd_max_length} || 1,
5004 $drive->{iops_wr_max_length} || 1);
5013 if ($drive->{file} eq 'none
') {
5014 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
5015 if (drive_is_cloudinit($old_drive)) {
5016 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
5019 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
5020 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
5021 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
5029 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
5031 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
5032 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive, $arch, $machine_type);
5036 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
5037 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
5039 PVE::QemuConfig->lock_config($vmid, sub {
5040 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
5042 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
5044 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5046 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
5048 if (!$statefile && scalar(keys %{$conf->{pending}})) {
5049 vmconfig_apply_pending($vmid, $conf, $storecfg);
5050 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
5053 PVE::QemuServer::Cloudinit::generate_cloudinitconfig($conf, $vmid);
5055 my $defaults = load_defaults();
5057 # set environment variable useful inside network script
5058 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
5060 my $local_volumes = {};
5062 if ($targetstorage) {
5063 foreach_drive($conf, sub {
5064 my ($ds, $drive) = @_;
5066 return if drive_is_cdrom($drive);
5068 my $volid = $drive->{file};
5072 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
5074 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5075 return if $scfg->{shared};
5076 $local_volumes->{$ds} = [$volid, $storeid, $volname];
5081 foreach my $opt (sort keys %$local_volumes) {
5083 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
5084 my $drive = parse_drive($opt, $conf->{$opt});
5086 #if remote storage is specified, use default format
5087 if ($targetstorage && $targetstorage ne "1") {
5088 $storeid = $targetstorage;
5089 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
5090 $format = $defFormat;
5092 #else we use same format than original
5093 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
5094 $format = qemu_img_format($scfg, $volid);
5097 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
5098 my $newdrive = $drive;
5099 $newdrive->{format} = $format;
5100 $newdrive->{file} = $newvolid;
5101 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
5102 $local_volumes->{$opt} = $drivestr;
5103 #pass drive to conf for command line
5104 $conf->{$opt} = $drivestr;
5108 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
5110 my $migrate_port = 0;
5113 if ($statefile eq 'tcp
') {
5114 my $localip = "localhost";
5115 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
5116 my $nodename = PVE::INotify::nodename();
5118 if (!defined($migration_type)) {
5119 if (defined($datacenterconf->{migration}->{type})) {
5120 $migration_type = $datacenterconf->{migration}->{type};
5122 $migration_type = 'secure
';
5126 if ($migration_type eq 'insecure
') {
5127 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5128 if ($migrate_network_addr) {
5129 $localip = $migrate_network_addr;
5131 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
5134 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5137 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5138 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5139 $migrate_uri = "tcp:${localip}:${migrate_port}";
5140 push @$cmd, '-incoming
', $migrate_uri;
5143 } elsif ($statefile eq 'unix
') {
5144 # should be default for secure migrations as a ssh TCP forward
5145 # tunnel is not deterministic reliable ready and fails regurarly
5146 # to set up in time, so use UNIX socket forwards
5147 my $socket_addr = "/run/qemu-server/$vmid.migrate";
5148 unlink $socket_addr;
5150 $migrate_uri = "unix:$socket_addr";
5152 push @$cmd, '-incoming
', $migrate_uri;
5156 push @$cmd, '-loadstate
', $statefile;
5163 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
5164 my $d = parse_hostpci($conf->{"hostpci$i"});
5166 my $pcidevices = $d->{pciid};
5167 foreach my $pcidevice (@$pcidevices) {
5168 my $pciid = $pcidevice->{id};
5170 my $info = PVE::SysFSTools::pci_device_info("0000:$pciid");
5171 die "IOMMU not present\n" if !PVE::SysFSTools::check_iommu_support();
5172 die "no pci device info for device '$pciid'\n" if !$info;
5175 my $uuid = PVE::SysFSTools::generate_mdev_uuid($vmid, $i);
5176 PVE::SysFSTools::pci_create_mdev_device($pciid, $uuid, $d->{mdev});
5178 die "can't unbind
/bind pci group to vfio
'$pciid'\n"
5179 if !PVE::SysFSTools::pci_dev_group_bind_to_vfio($pciid);
5180 die "can
't reset pci device '$pciid'\n"
5181 if $info->{has_fl_reset} and !PVE::SysFSTools::pci_dev_reset($info);
5186 PVE::Storage::activate_volumes($storecfg, $vollist);
5188 if (!check_running($vmid, 1)) {
5190 run_command(['/bin/systemctl
', 'stop
', "$vmid.scope"],
5191 outfunc => sub {}, errfunc => sub {});
5195 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
5196 : $defaults->{cpuunits};
5198 my $start_timeout = $conf->{hugepages} ? 300 : 30;
5199 my %run_params = (timeout => $statefile ? undef : $start_timeout, umask => 0077);
5202 Slice => 'qemu
.slice
',
5204 CPUShares => $cpuunits
5207 if (my $cpulimit = $conf->{cpulimit}) {
5208 $properties{CPUQuota} = int($cpulimit * 100);
5210 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
5212 my $run_qemu = sub {
5213 PVE::Tools::run_fork sub {
5214 PVE::Systemd::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
5215 run_command($cmd, %run_params);
5219 if ($conf->{hugepages}) {
5222 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
5223 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
5225 PVE::QemuServer::Memory::hugepages_mount();
5226 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
5228 eval { $run_qemu->() };
5230 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
5234 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
5236 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
5239 eval { $run_qemu->() };
5243 # deactivate volumes if start fails
5244 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
5245 die "start failed: $err";
5248 print "migration listens on $migrate_uri\n" if $migrate_uri;
5250 if ($statefile && $statefile ne 'tcp
' && $statefile ne 'unix
') {
5251 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
5255 #start nbd server for storage migration
5256 if ($targetstorage) {
5257 my $nodename = PVE::INotify::nodename();
5258 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
5259 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
5260 my $pfamily = PVE::Tools::get_host_address_family($nodename);
5261 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
5263 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${migrate_port}" } } );
5265 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
5267 foreach my $opt (sort keys %$local_volumes) {
5268 my $volid = $local_volumes->{$opt};
5269 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
5270 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
5271 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
5275 if ($migratedfrom) {
5277 set_migration_caps($vmid);
5282 print "spice listens on port $spice_port\n";
5283 if ($spice_ticket) {
5284 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
5285 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
5290 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
5291 if !$statefile && $conf->{balloon};
5293 foreach my $opt (keys %$conf) {
5294 next if $opt !~ m/^net\d+$/;
5295 my $nicconf = parse_net($conf->{$opt});
5296 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
5300 vm_mon_cmd_nocheck($vmid, 'qom-set
',
5301 path => "machine/peripheral/balloon0",
5302 property => "guest-stats-polling-interval",
5303 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
5309 my ($vmid, $execute, %params) = @_;
5311 my $cmd = { execute => $execute, arguments => \%params };
5312 vm_qmp_command($vmid, $cmd);
5315 sub vm_mon_cmd_nocheck {
5316 my ($vmid, $execute, %params) = @_;
5318 my $cmd = { execute => $execute, arguments => \%params };
5319 vm_qmp_command($vmid, $cmd, 1);
5322 sub vm_qmp_command {
5323 my ($vmid, $cmd, $nocheck) = @_;
5328 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
5329 $timeout = $cmd->{arguments}->{timeout};
5330 delete $cmd->{arguments}->{timeout};
5334 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
5335 my $sname = qmp_socket($vmid);
5336 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
5337 my $qmpclient = PVE::QMPClient->new();
5339 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
5341 die "unable to open monitor socket\n";
5345 syslog("err", "VM $vmid qmp command failed - $err");
5352 sub vm_human_monitor_command {
5353 my ($vmid, $cmdline) = @_;
5358 execute => 'human-monitor-command
',
5359 arguments => { 'command-line
' => $cmdline},
5362 return vm_qmp_command($vmid, $cmd);
5365 sub vm_commandline {
5366 my ($storecfg, $vmid) = @_;
5368 my $conf = PVE::QemuConfig->load_config($vmid);
5370 my $defaults = load_defaults();
5372 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
5374 return PVE::Tools::cmd2string($cmd);
5378 my ($vmid, $skiplock) = @_;
5380 PVE::QemuConfig->lock_config($vmid, sub {
5382 my $conf = PVE::QemuConfig->load_config($vmid);
5384 PVE::QemuConfig->check_lock($conf) if !$skiplock;
5386 vm_mon_cmd($vmid, "system_reset");
5390 sub get_vm_volumes {
5394 foreach_volid($conf, sub {
5395 my ($volid, $attr) = @_;
5397 return if $volid =~ m|^/|;
5399 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
5402 push @$vollist, $volid;
5408 sub vm_stop_cleanup {
5409 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
5414 my $vollist = get_vm_volumes($conf);
5415 PVE::Storage::deactivate_volumes($storecfg, $vollist);
5418 foreach my $ext (qw(mon qmp pid vnc qga)) {
5419 unlink "/var/run/qemu-server/${vmid}.$ext";
5422 foreach my $key (keys %$conf) {
5423 next if $key !~ m/^hostpci(\d+)$/;
5424 my $hostpciindex = $1;
5425 my $d = parse_hostpci
($conf->{$key});
5426 my $uuid = PVE
::SysFSTools
::generate_mdev_uuid
($vmid, $hostpciindex);
5428 foreach my $pci (@{$d->{pciid
}}) {
5429 my $pciid = $pci->{id
};
5430 PVE
::SysFSTools
::pci_cleanup_mdev_device
($pciid, $uuid);
5434 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
5436 warn $@ if $@; # avoid errors - just warn
5439 # Note: use $nockeck to skip tests if VM configuration file exists.
5440 # We need that when migration VMs to other nodes (files already moved)
5441 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
5443 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
5445 $force = 1 if !defined($force) && !$shutdown;
5448 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
5449 kill 15, $pid if $pid;
5450 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
5451 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
5455 PVE
::QemuConfig-
>lock_config($vmid, sub {
5457 my $pid = check_running
($vmid, $nocheck);
5462 $conf = PVE
::QemuConfig-
>load_config($vmid);
5463 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
5464 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
5465 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
5466 $timeout = $opts->{down
} if $opts->{down
};
5470 $timeout = 60 if !defined($timeout);
5474 if (defined($conf) && parse_guest_agent
($conf)->{enabled
}) {
5475 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
5477 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
5480 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
5487 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5492 if ($count >= $timeout) {
5494 warn "VM still running - terminating now with SIGTERM\n";
5497 die "VM quit/powerdown failed - got timeout\n";
5500 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5505 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
5508 die "VM quit/powerdown failed\n";
5516 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
5521 if ($count >= $timeout) {
5522 warn "VM still running - terminating now with SIGKILL\n";
5527 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
5532 my ($vmid, $skiplock) = @_;
5534 PVE
::QemuConfig-
>lock_config($vmid, sub {
5536 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5538 PVE
::QemuConfig-
>check_lock($conf)
5539 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5541 vm_mon_cmd
($vmid, "stop");
5546 my ($vmid, $skiplock, $nocheck) = @_;
5548 PVE
::QemuConfig-
>lock_config($vmid, sub {
5550 my $res = vm_mon_cmd
($vmid, 'query-status');
5551 my $resume_cmd = 'cont';
5553 if ($res->{status
} && $res->{status
} eq 'suspended') {
5554 $resume_cmd = 'system_wakeup';
5559 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5561 PVE
::QemuConfig-
>check_lock($conf)
5562 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
5564 vm_mon_cmd
($vmid, $resume_cmd);
5567 vm_mon_cmd_nocheck
($vmid, $resume_cmd);
5573 my ($vmid, $skiplock, $key) = @_;
5575 PVE
::QemuConfig-
>lock_config($vmid, sub {
5577 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5579 # there is no qmp command, so we use the human monitor command
5580 vm_human_monitor_command
($vmid, "sendkey $key");
5585 my ($storecfg, $vmid, $skiplock) = @_;
5587 PVE
::QemuConfig-
>lock_config($vmid, sub {
5589 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5591 if (!check_running
($vmid)) {
5592 destroy_vm
($storecfg, $vmid, undef, $skiplock);
5594 die "VM $vmid is running - destroy failed\n";
5599 # vzdump restore implementaion
5601 sub tar_archive_read_firstfile
{
5602 my $archive = shift;
5604 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5606 # try to detect archive type first
5607 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5608 die "unable to open file '$archive'\n";
5609 my $firstfile = <$fh>;
5613 die "ERROR: archive contaions no data\n" if !$firstfile;
5619 sub tar_restore_cleanup
{
5620 my ($storecfg, $statfile) = @_;
5622 print STDERR
"starting cleanup\n";
5624 if (my $fd = IO
::File-
>new($statfile, "r")) {
5625 while (defined(my $line = <$fd>)) {
5626 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5629 if ($volid =~ m
|^/|) {
5630 unlink $volid || die 'unlink failed\n';
5632 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5634 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5636 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5638 print STDERR
"unable to parse line in statfile - $line";
5645 sub restore_archive
{
5646 my ($archive, $vmid, $user, $opts) = @_;
5648 my $format = $opts->{format
};
5651 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5652 $format = 'tar' if !$format;
5654 } elsif ($archive =~ m/\.tar$/) {
5655 $format = 'tar' if !$format;
5656 } elsif ($archive =~ m/.tar.lzo$/) {
5657 $format = 'tar' if !$format;
5659 } elsif ($archive =~ m/\.vma$/) {
5660 $format = 'vma' if !$format;
5661 } elsif ($archive =~ m/\.vma\.gz$/) {
5662 $format = 'vma' if !$format;
5664 } elsif ($archive =~ m/\.vma\.lzo$/) {
5665 $format = 'vma' if !$format;
5668 $format = 'vma' if !$format; # default
5671 # try to detect archive format
5672 if ($format eq 'tar') {
5673 return restore_tar_archive
($archive, $vmid, $user, $opts);
5675 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5679 sub restore_update_config_line
{
5680 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5682 return if $line =~ m/^\#qmdump\#/;
5683 return if $line =~ m/^\#vzdump\#/;
5684 return if $line =~ m/^lock:/;
5685 return if $line =~ m/^unused\d+:/;
5686 return if $line =~ m/^parent:/;
5687 return if $line =~ m/^template:/; # restored VM is never a template
5689 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5690 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5691 # try to convert old 1.X settings
5692 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5693 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5694 my ($model, $macaddr) = split(/\=/, $devconfig);
5695 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5698 bridge
=> "vmbr$ind",
5699 macaddr
=> $macaddr,
5701 my $netstr = print_net
($net);
5703 print $outfd "net$cookie->{netcount}: $netstr\n";
5704 $cookie->{netcount
}++;
5706 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5707 my ($id, $netstr) = ($1, $2);
5708 my $net = parse_net
($netstr);
5709 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5710 $netstr = print_net
($net);
5711 print $outfd "$id: $netstr\n";
5712 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5715 my $di = parse_drive
($virtdev, $value);
5716 if (defined($di->{backup
}) && !$di->{backup
}) {
5717 print $outfd "#$line";
5718 } elsif ($map->{$virtdev}) {
5719 delete $di->{format
}; # format can change on restore
5720 $di->{file
} = $map->{$virtdev};
5721 $value = print_drive
($vmid, $di);
5722 print $outfd "$virtdev: $value\n";
5726 } elsif (($line =~ m/^vmgenid: (.*)/)) {
5728 if ($vmgenid ne '0') {
5729 # always generate a new vmgenid if there was a valid one setup
5730 $vmgenid = generate_uuid
();
5732 print $outfd "vmgenid: $vmgenid\n";
5733 } elsif (($line =~ m/^(smbios1: )(.*)/) && $unique) {
5734 my ($uuid, $uuid_str);
5735 UUID
::generate
($uuid);
5736 UUID
::unparse
($uuid, $uuid_str);
5737 my $smbios1 = parse_smbios1
($2);
5738 $smbios1->{uuid
} = $uuid_str;
5739 print $outfd $1.print_smbios1
($smbios1)."\n";
5746 my ($cfg, $vmid) = @_;
5748 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5750 my $volid_hash = {};
5751 foreach my $storeid (keys %$info) {
5752 foreach my $item (@{$info->{$storeid}}) {
5753 next if !($item->{volid
} && $item->{size
});
5754 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5755 $volid_hash->{$item->{volid
}} = $item;
5762 sub is_volume_in_use
{
5763 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5765 my $path = PVE
::Storage
::path
($storecfg, $volid);
5767 my $scan_config = sub {
5768 my ($cref, $snapname) = @_;
5770 foreach my $key (keys %$cref) {
5771 my $value = $cref->{$key};
5772 if (is_valid_drivename
($key)) {
5773 next if $skip_drive && $key eq $skip_drive;
5774 my $drive = parse_drive
($key, $value);
5775 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5776 return 1 if $volid eq $drive->{file
};
5777 if ($drive->{file
} =~ m!^/!) {
5778 return 1 if $drive->{file
} eq $path;
5780 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5782 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5784 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5792 return 1 if &$scan_config($conf);
5796 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5797 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5803 sub update_disksize
{
5804 my ($vmid, $conf, $volid_hash) = @_;
5807 my $prefix = "VM $vmid:";
5809 # used and unused disks
5810 my $referenced = {};
5812 # Note: it is allowed to define multiple storages with same path (alias), so
5813 # we need to check both 'volid' and real 'path' (two different volid can point
5814 # to the same path).
5816 my $referencedpath = {};
5819 foreach my $opt (keys %$conf) {
5820 if (is_valid_drivename
($opt)) {
5821 my $drive = parse_drive
($opt, $conf->{$opt});
5822 my $volid = $drive->{file
};
5825 $referenced->{$volid} = 1;
5826 if ($volid_hash->{$volid} &&
5827 (my $path = $volid_hash->{$volid}->{path
})) {
5828 $referencedpath->{$path} = 1;
5831 next if drive_is_cdrom
($drive);
5832 next if !$volid_hash->{$volid};
5834 $drive->{size
} = $volid_hash->{$volid}->{size
};
5835 my $new = print_drive
($vmid, $drive);
5836 if ($new ne $conf->{$opt}) {
5838 $conf->{$opt} = $new;
5839 print "$prefix update disk '$opt' information.\n";
5844 # remove 'unusedX' entry if volume is used
5845 foreach my $opt (keys %$conf) {
5846 next if $opt !~ m/^unused\d+$/;
5847 my $volid = $conf->{$opt};
5848 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5849 if ($referenced->{$volid} || ($path && $referencedpath->{$path})) {
5850 print "$prefix remove entry '$opt', its volume '$volid' is in use.\n";
5852 delete $conf->{$opt};
5855 $referenced->{$volid} = 1;
5856 $referencedpath->{$path} = 1 if $path;
5859 foreach my $volid (sort keys %$volid_hash) {
5860 next if $volid =~ m/vm-$vmid-state-/;
5861 next if $referenced->{$volid};
5862 my $path = $volid_hash->{$volid}->{path
};
5863 next if !$path; # just to be sure
5864 next if $referencedpath->{$path};
5866 my $key = PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5867 print "$prefix add unreferenced volume '$volid' as '$key' to config.\n";
5868 $referencedpath->{$path} = 1; # avoid to add more than once (aliases)
5875 my ($vmid, $nolock, $dryrun) = @_;
5877 my $cfg = PVE
::Storage
::config
();
5879 # FIXME: Remove once our RBD plugin can handle CT and VM on a single storage
5880 # see: https://pve.proxmox.com/pipermail/pve-devel/2018-July/032900.html
5881 foreach my $stor (keys %{$cfg->{ids
}}) {
5882 delete($cfg->{ids
}->{$stor}) if ! $cfg->{ids
}->{$stor}->{content
}->{images
};
5885 print "rescan volumes...\n";
5886 my $volid_hash = scan_volids
($cfg, $vmid);
5888 my $updatefn = sub {
5891 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5893 PVE
::QemuConfig-
>check_lock($conf);
5896 foreach my $volid (keys %$volid_hash) {
5897 my $info = $volid_hash->{$volid};
5898 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5901 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5903 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes && !$dryrun;
5906 if (defined($vmid)) {
5910 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5913 my $vmlist = config_list
();
5914 foreach my $vmid (keys %$vmlist) {
5918 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5924 sub restore_vma_archive
{
5925 my ($archive, $vmid, $user, $opts, $comp) = @_;
5927 my $readfrom = $archive;
5929 my $cfg = PVE
::Storage
::config
();
5931 my $bwlimit = $opts->{bwlimit
};
5933 my $dbg_cmdstring = '';
5934 my $add_pipe = sub {
5936 push @$commands, $cmd;
5937 $dbg_cmdstring .= ' | ' if length($dbg_cmdstring);
5938 $dbg_cmdstring .= PVE
::Tools
::cmd2string
($cmd);
5943 if ($archive eq '-') {
5946 # If we use a backup from a PVE defined storage we also consider that
5947 # storage's rate limit:
5948 my (undef, $volid) = PVE
::Storage
::path_to_volume_id
($cfg, $archive);
5949 if (defined($volid)) {
5950 my ($sid, undef) = PVE
::Storage
::parse_volume_id
($volid);
5951 my $readlimit = PVE
::Storage
::get_bandwidth_limit
('restore', [$sid], $bwlimit);
5953 print STDERR
"applying read rate limit: $readlimit\n";
5954 my $cstream = ['cstream', '-t', $readlimit*1024, '--', $readfrom];
5955 $add_pipe->($cstream);
5962 if ($comp eq 'gzip') {
5963 $cmd = ['zcat', $readfrom];
5964 } elsif ($comp eq 'lzop') {
5965 $cmd = ['lzop', '-d', '-c', $readfrom];
5967 die "unknown compression method '$comp'\n";
5972 my $tmpdir = "/var/tmp/vzdumptmp$$";
5975 # disable interrupts (always do cleanups)
5979 local $SIG{HUP
} = sub { warn "got interrupt - ignored\n"; };
5981 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
5982 POSIX
::mkfifo
($mapfifo, 0600);
5985 my $openfifo = sub {
5986 open($fifofh, '>', $mapfifo) || die $!;
5989 $add_pipe->(['vma', 'extract', '-v', '-r', $mapfifo, $readfrom, $tmpdir]);
5996 my $rpcenv = PVE
::RPCEnvironment
::get
();
5998 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5999 my $tmpfn = "$conffile.$$.tmp";
6001 # Note: $oldconf is undef if VM does not exists
6002 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
6003 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
6007 my $print_devmap = sub {
6008 my $virtdev_hash = {};
6010 my $cfgfn = "$tmpdir/qemu-server.conf";
6012 # we can read the config - that is already extracted
6013 my $fh = IO
::File-
>new($cfgfn, "r") ||
6014 "unable to read qemu-server.conf - $!\n";
6016 my $fwcfgfn = "$tmpdir/qemu-server.fw";
6018 my $pve_firewall_dir = '/etc/pve/firewall';
6019 mkdir $pve_firewall_dir; # make sure the dir exists
6020 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
6023 while (defined(my $line = <$fh>)) {
6024 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
6025 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
6026 die "archive does not contain data for drive '$virtdev'\n"
6027 if !$devinfo->{$devname};
6028 if (defined($opts->{storage
})) {
6029 $storeid = $opts->{storage
} || 'local';
6030 } elsif (!$storeid) {
6033 $format = 'raw' if !$format;
6034 $devinfo->{$devname}->{devname
} = $devname;
6035 $devinfo->{$devname}->{virtdev
} = $virtdev;
6036 $devinfo->{$devname}->{format
} = $format;
6037 $devinfo->{$devname}->{storeid
} = $storeid;
6039 # check permission on storage
6040 my $pool = $opts->{pool
}; # todo: do we need that?
6041 if ($user ne 'root@pam') {
6042 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
6045 $storage_limits{$storeid} = $bwlimit;
6047 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
6051 foreach my $key (keys %storage_limits) {
6052 my $limit = PVE
::Storage
::get_bandwidth_limit
('restore', [$key], $bwlimit);
6054 print STDERR
"rate limit for storage $key: $limit KiB/s\n";
6055 $storage_limits{$key} = $limit * 1024;
6058 foreach my $devname (keys %$devinfo) {
6059 die "found no device mapping information for device '$devname'\n"
6060 if !$devinfo->{$devname}->{virtdev
};
6063 # create empty/temp config
6065 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
6066 foreach_drive
($oldconf, sub {
6067 my ($ds, $drive) = @_;
6069 return if drive_is_cdrom
($drive);
6071 my $volid = $drive->{file
};
6073 return if !$volid || $volid =~ m
|^/|;
6075 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
6076 return if !$path || !$owner || ($owner != $vmid);
6078 # Note: only delete disk we want to restore
6079 # other volumes will become unused
6080 if ($virtdev_hash->{$ds}) {
6081 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
6088 # delete vmstate files
6089 # since after the restore we have no snapshots anymore
6090 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
6091 my $snap = $oldconf->{snapshots
}->{$snapname};
6092 if ($snap->{vmstate
}) {
6093 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
6102 foreach my $virtdev (sort keys %$virtdev_hash) {
6103 my $d = $virtdev_hash->{$virtdev};
6104 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
6105 my $storeid = $d->{storeid
};
6106 my $scfg = PVE
::Storage
::storage_config
($cfg, $storeid);
6109 if (my $limit = $storage_limits{$storeid}) {
6110 $map_opts .= "throttling.bps=$limit:throttling.group=$storeid:";
6113 # test if requested format is supported
6114 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $storeid);
6115 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
6116 $d->{format
} = $defFormat if !$supported;
6118 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $storeid, $vmid,
6119 $d->{format
}, undef, $alloc_size);
6120 print STDERR
"new volume ID is '$volid'\n";
6121 $d->{volid
} = $volid;
6122 my $path = PVE
::Storage
::path
($cfg, $volid);
6124 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
6126 my $write_zeros = 1;
6127 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
6131 print $fifofh "${map_opts}format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
6133 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
6134 $map->{$virtdev} = $volid;
6137 $fh->seek(0, 0) || die "seek failed - $!\n";
6139 my $outfd = new IO
::File
($tmpfn, "w") ||
6140 die "unable to write config for VM $vmid\n";
6142 my $cookie = { netcount
=> 0 };
6143 while (defined(my $line = <$fh>)) {
6144 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6157 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6158 local $SIG{ALRM
} = sub { die "got timeout\n"; };
6160 $oldtimeout = alarm($timeout);
6167 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
6168 my ($dev_id, $size, $devname) = ($1, $2, $3);
6169 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
6170 } elsif ($line =~ m/^CTIME: /) {
6171 # we correctly received the vma config, so we can disable
6172 # the timeout now for disk allocation (set to 10 minutes, so
6173 # that we always timeout if something goes wrong)
6176 print $fifofh "done\n";
6177 my $tmp = $oldtimeout || 0;
6178 $oldtimeout = undef;
6184 print "restore vma archive: $dbg_cmdstring\n";
6185 run_command
($commands, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
6189 alarm($oldtimeout) if $oldtimeout;
6192 foreach my $devname (keys %$devinfo) {
6193 my $volid = $devinfo->{$devname}->{volid
};
6194 push @$vollist, $volid if $volid;
6197 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
6205 foreach my $devname (keys %$devinfo) {
6206 my $volid = $devinfo->{$devname}->{volid
};
6209 if ($volid =~ m
|^/|) {
6210 unlink $volid || die 'unlink failed\n';
6212 PVE
::Storage
::vdisk_free
($cfg, $volid);
6214 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
6216 print STDERR
"unable to cleanup '$volid' - $@" if $@;
6223 rename($tmpfn, $conffile) ||
6224 die "unable to commit configuration file '$conffile'\n";
6226 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6228 eval { rescan
($vmid, 1); };
6232 sub restore_tar_archive
{
6233 my ($archive, $vmid, $user, $opts) = @_;
6235 if ($archive ne '-') {
6236 my $firstfile = tar_archive_read_firstfile
($archive);
6237 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
6238 if $firstfile ne 'qemu-server.conf';
6241 my $storecfg = PVE
::Storage
::config
();
6243 # destroy existing data - keep empty config
6244 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
6245 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
6247 my $tocmd = "/usr/lib/qemu-server/qmextract";
6249 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
6250 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
6251 $tocmd .= ' --prealloc' if $opts->{prealloc
};
6252 $tocmd .= ' --info' if $opts->{info
};
6254 # tar option "xf" does not autodetect compression when read from STDIN,
6255 # so we pipe to zcat
6256 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
6257 PVE
::Tools
::shellquote
("--to-command=$tocmd");
6259 my $tmpdir = "/var/tmp/vzdumptmp$$";
6262 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
6263 local $ENV{VZDUMP_VMID
} = $vmid;
6264 local $ENV{VZDUMP_USER
} = $user;
6266 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
6267 my $tmpfn = "$conffile.$$.tmp";
6269 # disable interrupts (always do cleanups)
6273 local $SIG{HUP
} = sub { print STDERR
"got interrupt - ignored\n"; };
6281 local $SIG{PIPE
} = sub { die "interrupted by signal\n"; };
6283 if ($archive eq '-') {
6284 print "extracting archive from STDIN\n";
6285 run_command
($cmd, input
=> "<&STDIN");
6287 print "extracting archive '$archive'\n";
6291 return if $opts->{info
};
6295 my $statfile = "$tmpdir/qmrestore.stat";
6296 if (my $fd = IO
::File-
>new($statfile, "r")) {
6297 while (defined (my $line = <$fd>)) {
6298 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
6299 $map->{$1} = $2 if $1;
6301 print STDERR
"unable to parse line in statfile - $line\n";
6307 my $confsrc = "$tmpdir/qemu-server.conf";
6309 my $srcfd = new IO
::File
($confsrc, "r") ||
6310 die "unable to open file '$confsrc'\n";
6312 my $outfd = new IO
::File
($tmpfn, "w") ||
6313 die "unable to write config for VM $vmid\n";
6315 my $cookie = { netcount
=> 0 };
6316 while (defined (my $line = <$srcfd>)) {
6317 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
6329 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
6336 rename $tmpfn, $conffile ||
6337 die "unable to commit configuration file '$conffile'\n";
6339 PVE
::Cluster
::cfs_update
(); # make sure we read new file
6341 eval { rescan
($vmid, 1); };
6345 sub foreach_storage_used_by_vm
{
6346 my ($conf, $func) = @_;
6350 foreach_drive
($conf, sub {
6351 my ($ds, $drive) = @_;
6352 return if drive_is_cdrom
($drive);
6354 my $volid = $drive->{file
};
6356 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
6357 $sidhash->{$sid} = $sid if $sid;
6360 foreach my $sid (sort keys %$sidhash) {
6365 sub do_snapshots_with_qemu
{
6366 my ($storecfg, $volid) = @_;
6368 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
6370 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
6371 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
6375 if ($volid =~ m/\.(qcow2|qed)$/){
6382 sub qga_check_running
{
6383 my ($vmid, $nowarn) = @_;
6385 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
6387 warn "Qemu Guest Agent is not running - $@" if !$nowarn;
6393 sub template_create
{
6394 my ($vmid, $conf, $disk) = @_;
6396 my $storecfg = PVE
::Storage
::config
();
6398 foreach_drive
($conf, sub {
6399 my ($ds, $drive) = @_;
6401 return if drive_is_cdrom
($drive);
6402 return if $disk && $ds ne $disk;
6404 my $volid = $drive->{file
};
6405 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
6407 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
6408 $drive->{file
} = $voliddst;
6409 $conf->{$ds} = print_drive
($vmid, $drive);
6410 PVE
::QemuConfig-
>write_config($vmid, $conf);
6414 sub qemu_img_convert
{
6415 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
6417 my $storecfg = PVE
::Storage
::config
();
6418 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
6419 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
6421 if ($src_storeid && $dst_storeid) {
6423 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
6425 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
6426 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6428 my $src_format = qemu_img_format
($src_scfg, $src_volname);
6429 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
6431 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
6432 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6435 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
6436 push @$cmd, '-l', "snapshot.name=$snapname" if($snapname && $src_format eq "qcow2");
6437 push @$cmd, '-t', 'none' if $dst_scfg->{type
} eq 'zfspool';
6438 push @$cmd, '-T', 'none' if $src_scfg->{type
} eq 'zfspool';
6439 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
6440 if ($is_zero_initialized) {
6441 push @$cmd, "zeroinit:$dst_path";
6443 push @$cmd, $dst_path;
6448 if($line =~ m/\((\S+)\/100\
%\)/){
6450 my $transferred = int($size * $percent / 100);
6451 my $remaining = $size - $transferred;
6453 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
6458 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
6460 die "copy failed: $err" if $err;
6464 sub qemu_img_format
{
6465 my ($scfg, $volname) = @_;
6467 if ($scfg->{path
} && $volname =~ m/\.($QEMU_FORMAT_RE)$/) {
6474 sub qemu_drive_mirror
{
6475 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga) = @_;
6477 $jobs = {} if !$jobs;
6481 $jobs->{"drive-$drive"} = {};
6483 if ($dst_volid =~ /^nbd:/) {
6484 $qemu_target = $dst_volid;
6487 my $storecfg = PVE
::Storage
::config
();
6488 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
6490 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
6492 $format = qemu_img_format
($dst_scfg, $dst_volname);
6494 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
6496 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
6499 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
6500 $opts->{format
} = $format if $format;
6502 print "drive mirror is starting for drive-$drive\n";
6504 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
6507 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6508 die "mirroring error: $err";
6511 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
6514 sub qemu_drive_mirror_monitor
{
6515 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
6518 my $err_complete = 0;
6521 die "storage migration timed out\n" if $err_complete > 300;
6523 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6525 my $running_mirror_jobs = {};
6526 foreach my $stat (@$stats) {
6527 next if $stat->{type
} ne 'mirror';
6528 $running_mirror_jobs->{$stat->{device
}} = $stat;
6531 my $readycounter = 0;
6533 foreach my $job (keys %$jobs) {
6535 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6536 print "$job : finished\n";
6537 delete $jobs->{$job};
6541 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6543 my $busy = $running_mirror_jobs->{$job}->{busy
};
6544 my $ready = $running_mirror_jobs->{$job}->{ready
};
6545 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6546 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6547 my $remaining = $total - $transferred;
6548 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6550 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6553 $readycounter++ if $running_mirror_jobs->{$job}->{ready
};
6556 last if scalar(keys %$jobs) == 0;
6558 if ($readycounter == scalar(keys %$jobs)) {
6559 print "all mirroring jobs are ready \n";
6560 last if $skipcomplete; #do the complete later
6562 if ($vmiddst && $vmiddst != $vmid) {
6563 my $agent_running = $qga && qga_check_running
($vmid);
6564 if ($agent_running) {
6565 print "freeze filesystem\n";
6566 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6568 print "suspend vm\n";
6569 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6572 # if we clone a disk for a new target vm, we don't switch the disk
6573 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6575 if ($agent_running) {
6576 print "unfreeze filesystem\n";
6577 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6579 print "resume vm\n";
6580 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6586 foreach my $job (keys %$jobs) {
6587 # try to switch the disk if source and destination are on the same guest
6588 print "$job: Completing block job...\n";
6590 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6591 if ($@ =~ m/cannot be completed/) {
6592 print "$job: Block job cannot be completed, try again.\n";
6595 print "$job: Completed successfully.\n";
6596 $jobs->{$job}->{complete
} = 1;
6607 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6608 die "mirroring error: $err";
6613 sub qemu_blockjobs_cancel
{
6614 my ($vmid, $jobs) = @_;
6616 foreach my $job (keys %$jobs) {
6617 print "$job: Cancelling block job\n";
6618 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6619 $jobs->{$job}->{cancel
} = 1;
6623 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6625 my $running_jobs = {};
6626 foreach my $stat (@$stats) {
6627 $running_jobs->{$stat->{device
}} = $stat;
6630 foreach my $job (keys %$jobs) {
6632 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6633 print "$job: Done.\n";
6634 delete $jobs->{$job};
6638 last if scalar(keys %$jobs) == 0;
6645 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6646 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;
6651 print "create linked clone of drive $drivename ($drive->{file})\n";
6652 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6653 push @$newvollist, $newvolid;
6656 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6657 $storeid = $storage if $storage;
6659 my $dst_format = resolve_dst_disk_format
($storecfg, $storeid, $volname, $format);
6660 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6662 print "create full clone of drive $drivename ($drive->{file})\n";
6664 if (drive_is_cloudinit
($drive)) {
6665 $name = "vm-$newvmid-cloudinit";
6667 # cloudinit only supports raw and qcow2 atm:
6668 if ($dst_format eq 'qcow2') {
6670 } elsif ($dst_format ne 'raw') {
6671 die "clone: unhandled format for cloudinit image\n";
6674 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
6675 push @$newvollist, $newvolid;
6677 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6679 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6680 if (!$running || $snapname) {
6681 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6684 my $kvmver = get_running_qemu_version
($vmid);
6685 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
6686 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6687 if $drive->{iothread
};
6690 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga);
6694 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6697 $disk->{format
} = undef;
6698 $disk->{file
} = $newvolid;
6699 $disk->{size
} = $size;
6704 # this only works if VM is running
6705 sub get_current_qemu_machine
{
6708 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
6709 my $res = vm_qmp_command
($vmid, $cmd);
6711 my ($current, $default);
6712 foreach my $e (@$res) {
6713 $default = $e->{name
} if $e->{'is-default'};
6714 $current = $e->{name
} if $e->{'is-current'};
6717 # fallback to the default machine if current is not supported by qemu
6718 return $current || $default || 'pc';
6721 sub get_running_qemu_version
{
6723 my $cmd = { execute
=> 'query-version', arguments
=> {} };
6724 my $res = vm_qmp_command
($vmid, $cmd);
6725 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6728 sub qemu_machine_feature_enabled
{
6729 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6734 if ($machine && $machine =~ m/^((?:pc(-i440fx|-q35)?|virt)-(\d+)\.(\d+))/) {
6736 $current_major = $3;
6737 $current_minor = $4;
6739 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6741 $current_major = $1;
6742 $current_minor = $2;
6745 return 1 if $current_major > $version_major ||
6746 ($current_major == $version_major &&
6747 $current_minor >= $version_minor);
6750 sub qemu_machine_pxe
{
6751 my ($vmid, $conf, $machine) = @_;
6753 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6755 if ($conf->{machine
} && $conf->{machine
} =~ m/\.pxe$/) {
6762 sub qemu_use_old_bios_files
{
6763 my ($machine_type) = @_;
6765 return if !$machine_type;
6767 my $use_old_bios_files = undef;
6769 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6771 $use_old_bios_files = 1;
6773 my $kvmver = kvm_user_version
();
6774 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6775 # load new efi bios files on migration. So this hack is required to allow
6776 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6777 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6778 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6781 return ($use_old_bios_files, $machine_type);
6784 sub create_efidisk
($$$$$) {
6785 my ($storecfg, $storeid, $vmid, $fmt, $arch) = @_;
6787 my (undef, $ovmf_vars) = get_ovmf_files
($arch);
6788 die "EFI vars default image not found\n" if ! -f
$ovmf_vars;
6790 my $vars_size = PVE
::Tools
::convert_size
(-s
$ovmf_vars, 'b' => 'kb');
6791 my $volid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $vmid, $fmt, undef, $vars_size);
6792 PVE
::Storage
::activate_volumes
($storecfg, [$volid]);
6794 my $path = PVE
::Storage
::path
($storecfg, $volid);
6796 run_command
(['/usr/bin/qemu-img', 'convert', '-n', '-f', 'raw', '-O', $fmt, $ovmf_vars, $path]);
6798 die "Copying EFI vars image failed: $@" if $@;
6800 return ($volid, $vars_size);
6803 sub vm_iothreads_list
{
6806 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6809 foreach my $iothread (@$res) {
6810 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6817 my ($conf, $drive) = @_;
6821 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)) {
6823 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6829 my $controller = int($drive->{index} / $maxdev);
6830 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6832 return ($maxdev, $controller, $controller_prefix);
6835 sub add_hyperv_enlightenments
{
6836 my ($cpuFlags, $winversion, $machine_type, $kvmver, $bios, $gpu_passthrough) = @_;
6838 return if $winversion < 6;
6839 return if $bios && $bios eq 'ovmf' && $winversion < 8;
6841 push @$cpuFlags , 'hv_vendor_id=proxmox' if $gpu_passthrough;
6843 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
6844 push @$cpuFlags , 'hv_spinlocks=0x1fff';
6845 push @$cpuFlags , 'hv_vapic';
6846 push @$cpuFlags , 'hv_time';
6848 push @$cpuFlags , 'hv_spinlocks=0xffff';
6851 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
6852 push @$cpuFlags , 'hv_reset';
6853 push @$cpuFlags , 'hv_vpindex';
6854 push @$cpuFlags , 'hv_runtime';
6857 if ($winversion >= 7) {
6858 push @$cpuFlags , 'hv_relaxed';
6860 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 12)) {
6861 push @$cpuFlags , 'hv_synic';
6862 push @$cpuFlags , 'hv_stimer';
6867 sub windows_version
{
6870 return 0 if !$ostype;
6874 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6876 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6878 } elsif ($ostype =~ m/^win(\d+)$/) {
6885 sub resolve_dst_disk_format
{
6886 my ($storecfg, $storeid, $src_volname, $format) = @_;
6887 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6890 # if no target format is specified, use the source disk format as hint
6892 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6893 $format = qemu_img_format
($scfg, $src_volname);
6899 # test if requested format is supported - else use default
6900 my $supported = grep { $_ eq $format } @$validFormats;
6901 $format = $defFormat if !$supported;
6905 sub resolve_first_disk
{
6907 my @disks = PVE
::QemuServer
::valid_drive_names
();
6909 foreach my $ds (reverse @disks) {
6910 next if !$conf->{$ds};
6911 my $disk = PVE
::QemuServer
::parse_drive
($ds, $conf->{$ds});
6912 next if PVE
::QemuServer
::drive_is_cdrom
($disk);
6919 my ($uuid, $uuid_str);
6920 UUID
::generate
($uuid);
6921 UUID
::unparse
($uuid, $uuid_str);
6925 sub generate_smbios1_uuid
{
6926 return "uuid=".generate_uuid
();
6932 vm_mon_cmd
($vmid, 'nbd-server-stop');
6935 # bash completion helper
6937 sub complete_backup_archives
{
6938 my ($cmdname, $pname, $cvalue) = @_;
6940 my $cfg = PVE
::Storage
::config
();
6944 if ($cvalue =~ m/^([^:]+):/) {
6948 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
6951 foreach my $id (keys %$data) {
6952 foreach my $item (@{$data->{$id}}) {
6953 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
6954 push @$res, $item->{volid
} if defined($item->{volid
});
6961 my $complete_vmid_full = sub {
6964 my $idlist = vmstatus
();
6968 foreach my $id (keys %$idlist) {
6969 my $d = $idlist->{$id};
6970 if (defined($running)) {
6971 next if $d->{template
};
6972 next if $running && $d->{status
} ne 'running';
6973 next if !$running && $d->{status
} eq 'running';
6982 return &$complete_vmid_full();
6985 sub complete_vmid_stopped
{
6986 return &$complete_vmid_full(0);
6989 sub complete_vmid_running
{
6990 return &$complete_vmid_full(1);
6993 sub complete_storage
{
6995 my $cfg = PVE
::Storage
::config
();
6996 my $ids = $cfg->{ids
};
6999 foreach my $sid (keys %$ids) {
7000 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
7001 next if !$ids->{$sid}->{content
}->{images
};