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);
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 Time
::HiRes
qw(gettimeofday);
37 use File
::Copy
qw(copy);
40 my $OVMF_CODE = '/usr/share/kvm/OVMF_CODE-pure-efi.fd';
41 my $OVMF_VARS = '/usr/share/kvm/OVMF_VARS-pure-efi.fd';
42 my $OVMF_IMG = '/usr/share/kvm/OVMF-pure-efi.fd';
44 my $qemu_snap_storage = {rbd
=> 1, sheepdog
=> 1};
46 my $cpuinfo = PVE
::ProcFSTools
::read_cpuinfo
();
48 # Note about locking: we use flock on the config file protect
49 # against concurent actions.
50 # Aditionaly, we have a 'lock' setting in the config file. This
51 # can be set to 'migrate', 'backup', 'snapshot' or 'rollback'. Most actions are not
52 # allowed when such lock is set. But you can ignore this kind of
53 # lock with the --skiplock flag.
55 cfs_register_file
('/qemu-server/',
59 PVE
::JSONSchema
::register_standard_option
('skiplock', {
60 description
=> "Ignore locks - only root is allowed to use this option.",
65 PVE
::JSONSchema
::register_standard_option
('pve-qm-stateuri', {
66 description
=> "Some command save/restore state from this location.",
72 PVE
::JSONSchema
::register_standard_option
('pve-snapshot-name', {
73 description
=> "The name of the snapshot.",
74 type
=> 'string', format
=> 'pve-configid',
78 PVE
::JSONSchema
::register_standard_option
('pve-qm-image-format', {
80 enum
=> [qw(raw cow qcow qed qcow2 vmdk cloop)],
81 description
=> "The drive's backing file's data format.",
85 #no warnings 'redefine';
88 my ($controller, $vmid, $option, $value) = @_;
90 my $path = "/sys/fs/cgroup/$controller/qemu.slice/$vmid.scope/$option";
91 PVE
::ProcFSTools
::write_proc_entry
($path, $value);
95 my $nodename = PVE
::INotify
::nodename
();
97 mkdir "/etc/pve/nodes/$nodename";
98 my $confdir = "/etc/pve/nodes/$nodename/qemu-server";
101 my $var_run_tmpdir = "/var/run/qemu-server";
102 mkdir $var_run_tmpdir;
104 my $lock_dir = "/var/lock/qemu-server";
107 my $pcisysfs = "/sys/bus/pci";
109 my $cpu_vendor_list = {
111 486 => 'GenuineIntel',
112 pentium
=> 'GenuineIntel',
113 pentium2
=> 'GenuineIntel',
114 pentium3
=> 'GenuineIntel',
115 coreduo
=> 'GenuineIntel',
116 core2duo
=> 'GenuineIntel',
117 Conroe
=> 'GenuineIntel',
118 Penryn
=> 'GenuineIntel',
119 Nehalem
=> 'GenuineIntel',
120 Westmere
=> 'GenuineIntel',
121 SandyBridge
=> 'GenuineIntel',
122 IvyBridge
=> 'GenuineIntel',
123 Haswell
=> 'GenuineIntel',
124 'Haswell-noTSX' => 'GenuineIntel',
125 Broadwell
=> 'GenuineIntel',
126 'Broadwell-noTSX' => 'GenuineIntel',
129 athlon
=> 'AuthenticAMD',
130 phenom
=> 'AuthenticAMD',
131 Opteron_G1
=> 'AuthenticAMD',
132 Opteron_G2
=> 'AuthenticAMD',
133 Opteron_G3
=> 'AuthenticAMD',
134 Opteron_G4
=> 'AuthenticAMD',
135 Opteron_G5
=> 'AuthenticAMD',
137 # generic types, use vendor from host node
147 description
=> "Emulated CPU type.",
149 enum
=> [ sort { "\L$a" cmp "\L$b" } keys %$cpu_vendor_list ],
154 description
=> "Do not identify as a KVM virtual machine.",
165 enum
=> [qw(i6300esb ib700)],
166 description
=> "Watchdog type to emulate.",
167 default => 'i6300esb',
172 enum
=> [qw(reset shutdown poweroff pause debug none)],
173 description
=> "The action to perform if after activation the guest fails to poll the watchdog in time.",
177 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', $watchdog_fmt);
183 description
=> "Specifies whether a VM will be started during system bootup.",
189 description
=> "Automatic restart after crash (currently ignored).",
194 type
=> 'string', format
=> 'pve-hotplug-features',
195 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'.",
196 default => 'network,disk,usb',
201 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
207 description
=> "Lock/unlock the VM.",
208 enum
=> [qw(migrate backup snapshot rollback)],
213 description
=> "Limit of CPU usage.",
214 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.",
222 description
=> "CPU weight for a VM.",
223 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.\n\nNOTE: You can disable fair-scheduler configuration by setting this to 0.",
231 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
238 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
244 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",
252 description
=> "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.conf' configuration file.",
253 enum
=> PVE
::Tools
::kvmkeymaplist
(),
258 type
=> 'string', format
=> 'dns-name',
259 description
=> "Set a name for the VM. Only used on the configuration web interface.",
264 description
=> "SCSI controller model",
265 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
271 description
=> "Description for the VM. Only used on the configuration web interface. This is saved as comment inside the configuration file.",
276 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 win10 l24 l26 solaris)],
277 description
=> "Specify guest operating system.",
278 verbose_description
=> <<EODESC,
279 Specify guest operating system. This is used to enable special
280 optimization/features for specific operating systems:
283 other;; unspecified OS
284 wxp;; Microsoft Windows XP
285 w2k;; Microsoft Windows 2000
286 w2k3;; Microsoft Windows 2003
287 w2k8;; Microsoft Windows 2008
288 wvista;; Microsoft Windows Vista
289 win7;; Microsoft Windows 7
290 win8;; Microsoft Windows 8/2012
291 l24;; Linux 2.4 Kernel
292 l26;; Linux 2.6/3.X Kernel
293 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
299 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
300 pattern
=> '[acdn]{1,4}',
305 type
=> 'string', format
=> 'pve-qm-bootdisk',
306 description
=> "Enable booting from specified disk.",
307 pattern
=> '(ide|sata|scsi|virtio)\d+',
312 description
=> "The number of CPUs. Please use option -sockets instead.",
319 description
=> "The number of CPU sockets.",
326 description
=> "The number of cores per socket.",
333 description
=> "Enable/disable NUMA.",
339 description
=> "Enable/disable hugepages memory.",
340 enum
=> [qw(any 2 1024)],
345 description
=> "Number of hotplugged vcpus.",
352 description
=> "Enable/disable ACPI.",
358 description
=> "Enable/disable Qemu GuestAgent.",
364 description
=> "Enable/disable KVM hardware virtualization.",
370 description
=> "Enable/disable time drift fix.",
376 description
=> "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
381 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
386 description
=> "Select the VGA type.",
387 verbose_description
=> "Select the VGA type. If you want to use high resolution" .
388 " modes (>= 1280x1024x16) then you should use the options " .
389 "'std' or 'vmware'. Default is 'std' for win8/win7/w2k8, and " .
390 "'cirrus' for other OS types. The 'qxl' option enables the SPICE " .
391 "display sever. For win* OS you can select how many independent " .
392 "displays you want, Linux guests can add displays them self. " .
393 "You can also run without any graphic card, using a serial device" .
395 enum
=> [qw(std cirrus vmware qxl serial0 serial1 serial2 serial3 qxl2 qxl3 qxl4)],
399 type
=> 'string', format
=> 'pve-qm-watchdog',
400 description
=> "Create a virtual hardware watchdog device.",
401 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled" .
402 " (by a guest action), the watchdog must be periodically polled " .
403 "by an agent inside the guest or else the watchdog will reset " .
404 "the guest (or execute the respective action specified)",
409 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
410 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'.",
411 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
414 startup
=> get_standard_option
('pve-startup-order'),
418 description
=> "Enable/disable Template.",
424 description
=> "Arbitrary arguments passed to kvm.",
425 verbose_description
=> <<EODESCR,
426 Arbitrary arguments passed to kvm, for example:
428 args: -no-reboot -no-hpet
430 NOTE: this option is for experts only.
437 description
=> "Enable/disable the USB tablet device.",
438 verbose_description
=> "Enable/disable the USB tablet device. This device is " .
439 "usually needed to allow absolute mouse positioning with VNC. " .
440 "Else the mouse runs out of sync with normal VNC clients. " .
441 "If you're running lots of console-only guests on one host, " .
442 "you may consider disabling this to save some context switches. " .
443 "This is turned off by default if you use spice (-vga=qxl).",
448 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
452 migrate_downtime
=> {
455 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
461 type
=> 'string', format
=> 'pve-qm-ide',
462 typetext
=> '<volume>',
463 description
=> "This is an alias for option -ide2",
467 description
=> "Emulated CPU type.",
471 parent
=> get_standard_option
('pve-snapshot-name', {
473 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
477 description
=> "Timestamp for snapshots.",
483 type
=> 'string', format
=> 'pve-volume-id',
484 description
=> "Reference to a volume which stores the VM state. This is used internally for snapshots.",
487 description
=> "Specific the Qemu machine type.",
489 pattern
=> '(pc|pc(-i440fx)?-\d+\.\d+(\.pxe)?|q35|pc-q35-\d+\.\d+(\.pxe)?)',
494 description
=> "Specify SMBIOS type 1 fields.",
495 type
=> 'string', format
=> 'pve-qm-smbios1',
502 description
=> "Sets the protection flag of the VM. This will disable the remove VM and remove disk operations.",
508 enum
=> [ qw(seabios ovmf) ],
509 description
=> "Select BIOS implementation.",
510 default => 'seabios',
514 # what about other qemu settings ?
516 #machine => 'string',
529 ##soundhw => 'string',
531 while (my ($k, $v) = each %$confdesc) {
532 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
535 my $MAX_IDE_DISKS = 4;
536 my $MAX_SCSI_DISKS = 14;
537 my $MAX_VIRTIO_DISKS = 16;
538 my $MAX_SATA_DISKS = 6;
539 my $MAX_USB_DEVICES = 5;
541 my $MAX_UNUSED_DISKS = 8;
542 my $MAX_HOSTPCI_DEVICES = 4;
543 my $MAX_SERIAL_PORTS = 4;
544 my $MAX_PARALLEL_PORTS = 3;
550 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
551 description
=> "CPUs accessing this NUMA node.",
552 format_description
=> "id[-id];...",
556 description
=> "Amount of memory this NUMA node provides.",
561 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
562 description
=> "Host NUMA nodes to use.",
563 format_description
=> "id[-id];...",
568 enum
=> [qw(preferred bind interleave)],
569 description
=> "NUMA allocation policy.",
573 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
576 type
=> 'string', format
=> $numa_fmt,
577 description
=> "NUMA topology.",
579 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
581 for (my $i = 0; $i < $MAX_NUMA; $i++) {
582 $confdesc->{"numa$i"} = $numadesc;
585 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
586 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
587 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
588 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
590 my $net_fmt_bridge_descr = <<__EOD__;
591 Bridge to attach the network device to. The Proxmox VE standard bridge
594 If you do not specify a bridge, we create a kvm user (NATed) network
595 device, which provides DHCP and DNS services. The following addresses
602 The DHCP server assign addresses to the guest starting from 10.0.2.15.
608 pattern
=> qr/[0-9a-f]{2}(?::[0-9a-f]{2}){5}/i,
609 description
=> "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
610 format_description
=> "XX:XX:XX:XX:XX:XX",
615 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'.",
616 enum
=> $nic_model_list,
619 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
622 description
=> $net_fmt_bridge_descr,
623 format_description
=> 'bridge',
628 minimum
=> 0, maximum
=> 16,
629 description
=> 'Number of packet queues to be used on the device.',
635 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
640 minimum
=> 1, maximum
=> 4094,
641 description
=> 'VLAN tag to apply to packets on this interface.',
646 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
647 description
=> 'VLAN trunks to pass through this interface.',
648 format_description
=> 'vlanid[;vlanid...]',
653 description
=> 'Whether this interface should be protected by the firewall.',
658 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
665 type
=> 'string', format
=> $net_fmt,
666 description
=> "Specify network devices.",
669 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
671 for (my $i = 0; $i < $MAX_NETS; $i++) {
672 $confdesc->{"net$i"} = $netdesc;
675 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
676 sub verify_volume_id_or_qm_path
{
677 my ($volid, $noerr) = @_;
679 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
683 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
684 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
686 return undef if $noerr;
694 my %drivedesc_base = (
695 volume
=> { alias
=> 'file' },
698 format
=> 'pve-volume-id-or-qm-path',
700 format_description
=> 'volume',
701 description
=> "The drive's backing volume.",
705 enum
=> [qw(cdrom disk)],
706 description
=> "The drive's media type.",
712 description
=> "Force the drive's physical geometry to have a specific cylinder count.",
717 description
=> "Force the drive's physical geometry to have a specific head count.",
722 description
=> "Force the drive's physical geometry to have a specific sector count.",
727 enum
=> [qw(none lba auto)],
728 description
=> "Force disk geometry bios translation mode.",
733 description
=> "Whether the drive should be included when making snapshots.",
738 enum
=> [qw(none writethrough writeback unsafe directsync)],
739 description
=> "The drive's cache mode",
742 format
=> get_standard_option
('pve-qm-image-format'),
745 format
=> 'disk-size',
746 format_description
=> 'DiskSize',
747 description
=> "Disk size. This is purely informational and has no effect.",
752 description
=> "Whether the drive should be included when making backups.",
757 enum
=> [qw(enospc ignore report stop)],
758 description
=> 'Write error action.',
763 enum
=> [qw(native threads)],
764 description
=> 'AIO type to use.',
769 enum
=> [qw(ignore on)],
770 description
=> 'Controls whether to pass discard/trim requests to the underlying storage.',
775 description
=> 'Controls whether to detect and try to optimize writes of zeroes.',
780 format
=> 'urlencoded',
781 format_description
=> 'serial',
782 maxLength
=> 20*3, # *3 since it's %xx url enoded
783 description
=> "The drive's reported serial number, url-encoded, up to 20 bytes long.",
791 enum
=> [qw(ignore report stop)],
792 description
=> 'Read error action.',
797 my %iothread_fmt = ( iothread
=> {
799 description
=> "Whether to use iothreads for this drive",
806 format
=> 'urlencoded',
807 format_description
=> 'model',
808 maxLength
=> 40*3, # *3 since it's %xx url enoded
809 description
=> "The drive's reported model name, url-encoded, up to 40 bytes long.",
817 description
=> "Number of queues.",
823 my $add_throttle_desc = sub {
824 my ($key, $type, $what, $unit, $longunit, $minimum) = @_;
827 format_description
=> $unit,
828 description
=> "Maximum $what in $longunit.",
831 $d->{minimum
} = $minimum if defined($minimum);
832 $drivedesc_base{$key} = $d;
834 # throughput: (leaky bucket)
835 $add_throttle_desc->('bps', 'integer', 'r/w speed', 'bps', 'bytes per second');
836 $add_throttle_desc->('bps_rd', 'integer', 'read speed', 'bps', 'bytes per second');
837 $add_throttle_desc->('bps_wr', 'integer', 'write speed', 'bps', 'bytes per second');
838 $add_throttle_desc->('mbps', 'number', 'r/w speed', 'mbps', 'megabytes per second');
839 $add_throttle_desc->('mbps_rd', 'number', 'read speed', 'mbps', 'megabytes per second');
840 $add_throttle_desc->('mbps_wr', 'number', 'write speed', 'mbps', 'megabytes per second');
841 $add_throttle_desc->('iops', 'integer', 'r/w I/O', 'iops', 'operations per second');
842 $add_throttle_desc->('iops_rd', 'integer', 'read I/O', 'iops', 'operations per second');
843 $add_throttle_desc->('iops_wr', 'integer', 'write I/O', 'iops', 'operations per second');
845 # pools: (pool of IO before throttling starts taking effect)
846 $add_throttle_desc->('mbps_max', 'number', 'unthrottled r/w pool', 'mbps', 'megabytes per second');
847 $add_throttle_desc->('mbps_rd_max', 'number', 'unthrottled read pool', 'mbps', 'megabytes per second');
848 $add_throttle_desc->('mbps_wr_max', 'number', 'unthrottled write pool', 'mbps', 'megabytes per second');
849 $add_throttle_desc->('iops_max', 'integer', 'unthrottled r/w I/O pool', 'iops', 'operations per second');
850 $add_throttle_desc->('iops_rd_max', 'integer', 'unthrottled read I/O pool', 'iops', 'operations per second');
851 $add_throttle_desc->('iops_wr_max', 'integer', 'unthrottled write I/O pool', 'iops', 'operations per second');
854 $add_throttle_desc->('bps_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
855 $add_throttle_desc->('bps_rd_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
856 $add_throttle_desc->('bps_wr_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
857 $add_throttle_desc->('iops_max_length', 'integer', 'length of I/O bursts', 'seconds', 'seconds', 1);
858 $add_throttle_desc->('iops_rd_length', 'integer', 'length of read I/O bursts', 'seconds', 'seconds', 1);
859 $add_throttle_desc->('iops_wr_length', 'integer', 'length of write I/O bursts', 'seconds', 'seconds', 1);
866 PVE
::JSONSchema
::register_format
("pve-qm-ide", $ide_fmt);
870 type
=> 'string', format
=> $ide_fmt,
871 description
=> "Use volume as IDE hard disk or CD-ROM (n is 0 to " .($MAX_IDE_DISKS -1) . ").",
873 PVE
::JSONSchema
::register_standard_option
("pve-qm-ide", $idedesc);
882 type
=> 'string', format
=> $scsi_fmt,
883 description
=> "Use volume as SCSI hard disk or CD-ROM (n is 0 to " . ($MAX_SCSI_DISKS - 1) . ").",
885 PVE
::JSONSchema
::register_standard_option
("pve-qm-scsi", $scsidesc);
893 type
=> 'string', format
=> $sata_fmt,
894 description
=> "Use volume as SATA hard disk or CD-ROM (n is 0 to " . ($MAX_SATA_DISKS - 1). ").",
896 PVE
::JSONSchema
::register_standard_option
("pve-qm-sata", $satadesc);
905 type
=> 'string', format
=> $virtio_fmt,
906 description
=> "Use volume as VIRTIO hard disk (n is 0 to " . ($MAX_VIRTIO_DISKS - 1) . ").",
908 PVE
::JSONSchema
::register_standard_option
("pve-qm-virtio", $virtiodesc);
919 volume
=> { alias
=> 'file' },
922 format
=> 'pve-volume-id-or-qm-path',
924 format_description
=> 'volume',
925 description
=> "The drive's backing volume.",
927 format
=> get_standard_option
('pve-qm-image-format'),
930 format
=> 'disk-size',
931 format_description
=> 'DiskSize',
932 description
=> "Disk size. This is purely informational and has no effect.",
939 type
=> 'string', format
=> $efidisk_fmt,
940 description
=> "Configure a Disk for storing EFI vars",
943 PVE
::JSONSchema
::register_standard_option
("pve-qm-efidisk", $efidisk_desc);
948 type
=> 'string', format
=> 'pve-qm-usb-device',
949 format_description
=> 'HOSTUSBDEVICE|spice',
950 description
=> <<EODESCR,
951 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
953 'bus-port(.port)*' (decimal numbers) or
954 'vendor_id:product_id' (hexadeciaml numbers) or
957 You can use the 'lsusb -t' command to list existing usb devices.
959 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
961 The value 'spice' can be used to add a usb redirection devices for spice.
967 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).",
974 type
=> 'string', format
=> $usb_fmt,
975 description
=> "Configure an USB device (n is 0 to 4).",
977 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
979 # NOTE: the match-groups of this regex are used in parse_hostpci
980 my $PCIRE = qr/([a-f0-9]{2}:[a-f0-9]{2})(?:\.([a-f0-9]))?/;
985 pattern
=> qr/$PCIRE(;$PCIRE)*/,
986 format_description
=> 'HOSTPCIID[;HOSTPCIID2...]',
987 description
=> <<EODESCR,
988 Host PCI device pass through. The PCI ID of a host's PCI device or a list
989 of PCI virtual functions of the host. HOSTPCIID syntax is:
991 'bus:dev.func' (hexadecimal numbers)
993 You can us the 'lspci' command to list existing PCI devices.
998 description
=> "Specify whether or not the device's ROM will be visible in the guest's memory map.",
1004 description
=> "Choose the PCI-express bus (needs the 'q35' machine model).",
1010 description
=> "Enable vfio-vga device support.",
1015 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', $hostpci_fmt);
1019 type
=> 'string', format
=> 'pve-qm-hostpci',
1020 description
=> "Map host PCI devices into guest.",
1021 verbose_description
=> <<EODESCR,
1022 Map host PCI devices into guest.
1024 NOTE: This option allows direct access to host hardware. So it is no longer
1025 possible to migrate such machines - use with special care.
1027 CAUTION: Experimental! User reported problems with this option.
1030 PVE
::JSONSchema
::register_standard_option
("pve-qm-hostpci", $hostpcidesc);
1035 pattern
=> '(/dev/.+|socket)',
1036 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1037 verbose_description
=> <<EODESCR,
1038 Create a serial device inside the VM (n is 0 to 3), and pass through a
1039 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1040 host side (use 'qm terminal' to open a terminal connection).
1042 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
1044 CAUTION: Experimental! User reported problems with this option.
1051 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1052 description
=> "Map host parallel devices (n is 0 to 2).",
1053 verbose_description
=> <<EODESCR,
1054 Map host parallel devices (n is 0 to 2).
1056 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1058 CAUTION: Experimental! User reported problems with this option.
1062 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1063 $confdesc->{"parallel$i"} = $paralleldesc;
1066 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1067 $confdesc->{"serial$i"} = $serialdesc;
1070 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
1071 $confdesc->{"hostpci$i"} = $hostpcidesc;
1074 for (my $i = 0; $i < $MAX_IDE_DISKS; $i++) {
1075 $drivename_hash->{"ide$i"} = 1;
1076 $confdesc->{"ide$i"} = $idedesc;
1079 for (my $i = 0; $i < $MAX_SATA_DISKS; $i++) {
1080 $drivename_hash->{"sata$i"} = 1;
1081 $confdesc->{"sata$i"} = $satadesc;
1084 for (my $i = 0; $i < $MAX_SCSI_DISKS; $i++) {
1085 $drivename_hash->{"scsi$i"} = 1;
1086 $confdesc->{"scsi$i"} = $scsidesc ;
1089 for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++) {
1090 $drivename_hash->{"virtio$i"} = 1;
1091 $confdesc->{"virtio$i"} = $virtiodesc;
1094 $drivename_hash->{efidisk0
} = 1;
1095 $confdesc->{efidisk0
} = $efidisk_desc;
1097 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1098 $confdesc->{"usb$i"} = $usbdesc;
1103 type
=> 'string', format
=> 'pve-volume-id',
1104 description
=> "Reference to unused volumes. This is used internally, and should not be modified manually.",
1107 for (my $i = 0; $i < $MAX_UNUSED_DISKS; $i++) {
1108 $confdesc->{"unused$i"} = $unuseddesc;
1111 my $kvm_api_version = 0;
1115 return $kvm_api_version if $kvm_api_version;
1117 my $fh = IO
::File-
>new("</dev/kvm") ||
1120 if (my $v = $fh->ioctl(KVM_GET_API_VERSION
(), 0)) {
1121 $kvm_api_version = $v;
1126 return $kvm_api_version;
1129 my $kvm_user_version;
1131 sub kvm_user_version
{
1133 return $kvm_user_version if $kvm_user_version;
1135 $kvm_user_version = 'unknown';
1139 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1140 $kvm_user_version = $2;
1144 eval { run_command
("kvm -version", outfunc
=> $code); };
1147 return $kvm_user_version;
1151 my $kernel_has_vhost_net = -c
'/dev/vhost-net';
1153 sub valid_drive_names
{
1154 # order is important - used to autoselect boot disk
1155 return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
1156 (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
1157 (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))),
1158 (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))),
1162 sub is_valid_drivename
{
1165 return defined($drivename_hash->{$dev});
1170 return defined($confdesc->{$key});
1174 return $nic_model_list;
1177 sub os_list_description
{
1181 wxp
=> 'Windows XP',
1182 w2k
=> 'Windows 2000',
1183 w2k3
=>, 'Windows 2003',
1184 w2k8
=> 'Windows 2008',
1185 wvista
=> 'Windows Vista',
1186 win7
=> 'Windows 7',
1187 win8
=> 'Windows 8/2012',
1188 win10
=> 'Windows 10/2016',
1196 sub get_cdrom_path
{
1198 return $cdrom_path if $cdrom_path;
1200 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1201 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1202 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1206 my ($storecfg, $vmid, $cdrom) = @_;
1208 if ($cdrom eq 'cdrom') {
1209 return get_cdrom_path
();
1210 } elsif ($cdrom eq 'none') {
1212 } elsif ($cdrom =~ m
|^/|) {
1215 return PVE
::Storage
::path
($storecfg, $cdrom);
1219 # try to convert old style file names to volume IDs
1220 sub filename_to_volume_id
{
1221 my ($vmid, $file, $media) = @_;
1223 if (!($file eq 'none' || $file eq 'cdrom' ||
1224 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1226 return undef if $file =~ m
|/|;
1228 if ($media && $media eq 'cdrom') {
1229 $file = "local:iso/$file";
1231 $file = "local:$vmid/$file";
1238 sub verify_media_type
{
1239 my ($opt, $vtype, $media) = @_;
1244 if ($media eq 'disk') {
1246 } elsif ($media eq 'cdrom') {
1249 die "internal error";
1252 return if ($vtype eq $etype);
1254 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1257 sub cleanup_drive_path
{
1258 my ($opt, $storecfg, $drive) = @_;
1260 # try to convert filesystem paths to volume IDs
1262 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1263 ($drive->{file
} !~ m
|^/dev/.+|) &&
1264 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1265 ($drive->{file
} !~ m/^\d+$/)) {
1266 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1267 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1268 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1269 verify_media_type
($opt, $vtype, $drive->{media
});
1270 $drive->{file
} = $volid;
1273 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1276 sub parse_hotplug_features
{
1281 return $res if $data eq '0';
1283 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1285 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1286 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1289 die "invalid hotplug feature '$feature'\n";
1295 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1296 sub pve_verify_hotplug_features
{
1297 my ($value, $noerr) = @_;
1299 return $value if parse_hotplug_features
($value);
1301 return undef if $noerr;
1303 die "unable to parse hotplug option\n";
1306 # ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
1307 # [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
1308 # [,rerror=ignore|report|stop][,werror=enospc|ignore|report|stop]
1309 # [,aio=native|threads][,discard=ignore|on][,detect_zeroes=on|off]
1310 # [,iothread=on][,serial=serial][,model=model]
1313 my ($key, $data) = @_;
1315 my ($interface, $index);
1317 if ($key =~ m/^([^\d]+)(\d+)$/) {
1324 my $desc = $key =~ /^unused\d+$/ ?
$alldrive_fmt
1325 : $confdesc->{$key}->{format
};
1327 warn "invalid drive key: $key\n";
1330 my $res = eval { PVE
::JSONSchema
::parse_property_string
($desc, $data) };
1331 return undef if !$res;
1332 $res->{interface
} = $interface;
1333 $res->{index} = $index;
1336 foreach my $opt (qw(bps bps_rd bps_wr)) {
1337 if (my $bps = defined(delete $res->{$opt})) {
1338 if (defined($res->{"m$opt"})) {
1339 warn "both $opt and m$opt specified\n";
1343 $res->{"m$opt"} = sprintf("%.3f", $bps / (1024*1024.0));
1347 # can't use the schema's 'requires' because of the mbps* => bps* "transforming aliases"
1348 for my $requirement (
1349 [bps_max_length
=> 'mbps_max'],
1350 [bps_rd_max_length
=> 'mbps_rd_max'],
1351 [bps_wr_max_length
=> 'mbps_wr_max'],
1352 [iops_max_length
=> 'iops_max'],
1353 [iops_rd_max_length
=> 'iops_rd_max'],
1354 [iops_wr_max_length
=> 'iops_wr_max']) {
1355 my ($option, $requires) = @$requirement;
1356 if ($res->{$option} && !$res->{$requires}) {
1357 warn "$option requires $requires\n";
1362 return undef if $error;
1364 return undef if $res->{mbps_rd
} && $res->{mbps
};
1365 return undef if $res->{mbps_wr
} && $res->{mbps
};
1366 return undef if $res->{iops_rd
} && $res->{iops
};
1367 return undef if $res->{iops_wr
} && $res->{iops
};
1369 if ($res->{media
} && ($res->{media
} eq 'cdrom')) {
1370 return undef if $res->{snapshot
} || $res->{trans
} || $res->{format
};
1371 return undef if $res->{heads
} || $res->{secs
} || $res->{cyls
};
1372 return undef if $res->{interface
} eq 'virtio';
1375 if (my $size = $res->{size
}) {
1376 return undef if !defined($res->{size
} = PVE
::JSONSchema
::parse_size
($size));
1383 my ($vmid, $drive) = @_;
1384 my $data = { %$drive };
1385 delete $data->{$_} for qw(index interface);
1386 return PVE
::JSONSchema
::print_property_string
($data, $alldrive_fmt);
1390 my($fh, $noerr) = @_;
1393 my $SG_GET_VERSION_NUM = 0x2282;
1395 my $versionbuf = "\x00" x
8;
1396 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1398 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1401 my $version = unpack("I", $versionbuf);
1402 if ($version < 30000) {
1403 die "scsi generic interface too old\n" if !$noerr;
1407 my $buf = "\x00" x
36;
1408 my $sensebuf = "\x00" x
8;
1409 my $cmd = pack("C x3 C x1", 0x12, 36);
1411 # see /usr/include/scsi/sg.h
1412 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";
1414 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1415 length($sensebuf), 0, length($buf), $buf,
1416 $cmd, $sensebuf, 6000);
1418 $ret = ioctl($fh, $SG_IO, $packet);
1420 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1424 my @res = unpack($sg_io_hdr_t, $packet);
1425 if ($res[17] || $res[18]) {
1426 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1431 (my $byte0, my $byte1, $res->{vendor
},
1432 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1434 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1435 $res->{type
} = $byte0 & 31;
1443 my $fh = IO
::File-
>new("+<$path") || return undef;
1444 my $res = scsi_inquiry
($fh, 1);
1450 sub machine_type_is_q35
{
1453 return $conf->{machine
} && ($conf->{machine
} =~ m/q35/) ?
1 : 0;
1456 sub print_tabletdevice_full
{
1459 my $q35 = machine_type_is_q35
($conf);
1461 # we use uhci for old VMs because tablet driver was buggy in older qemu
1462 my $usbbus = $q35 ?
"ehci" : "uhci";
1464 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1467 sub print_drivedevice_full
{
1468 my ($storecfg, $conf, $vmid, $drive, $bridges) = @_;
1473 if ($drive->{interface
} eq 'virtio') {
1474 my $pciaddr = print_pci_addr
("$drive->{interface}$drive->{index}", $bridges);
1475 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1476 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread
};
1477 } elsif ($drive->{interface
} eq 'scsi') {
1479 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1480 my $unit = $drive->{index} % $maxdev;
1481 my $devicetype = 'hd';
1483 if (drive_is_cdrom
($drive)) {
1486 if ($drive->{file
} =~ m
|^/|) {
1487 $path = $drive->{file
};
1488 if (my $info = path_is_scsi
($path)) {
1489 if ($info->{type
} == 0) {
1490 $devicetype = 'block';
1491 } elsif ($info->{type
} == 1) { # tape
1492 $devicetype = 'generic';
1496 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1499 if($path =~ m/^iscsi\:\/\
//){
1500 $devicetype = 'generic';
1504 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1505 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1507 $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}";
1510 } elsif ($drive->{interface
} eq 'ide'){
1512 my $controller = int($drive->{index} / $maxdev);
1513 my $unit = $drive->{index} % $maxdev;
1514 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1516 $device = "ide-$devicetype,bus=ide.$controller,unit=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1517 if ($devicetype eq 'hd' && (my $model = $drive->{model
})) {
1518 $model = URI
::Escape
::uri_unescape
($model);
1519 $device .= ",model=$model";
1521 } elsif ($drive->{interface
} eq 'sata'){
1522 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
1523 my $unit = $drive->{index} % $MAX_SATA_DISKS;
1524 $device = "ide-drive,bus=ahci$controller.$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1525 } elsif ($drive->{interface
} eq 'usb') {
1527 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1529 die "unsupported interface type";
1532 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1537 sub get_initiator_name
{
1540 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return undef;
1541 while (defined(my $line = <$fh>)) {
1542 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1551 sub print_drive_full
{
1552 my ($storecfg, $vmid, $drive) = @_;
1555 my $volid = $drive->{file
};
1558 if (drive_is_cdrom
($drive)) {
1559 $path = get_iso_path
($storecfg, $vmid, $volid);
1561 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1563 $path = PVE
::Storage
::path
($storecfg, $volid);
1564 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1565 $format = qemu_img_format
($scfg, $volname);
1573 my @qemu_drive_options = qw(heads secs cyls trans media format cache snapshot rerror werror aio discard iops iops_rd iops_wr iops_max iops_rd_max iops_wr_max);
1574 foreach my $o (@qemu_drive_options) {
1575 $opts .= ",$o=$drive->{$o}" if $drive->{$o};
1577 if (my $serial = $drive->{serial
}) {
1578 $serial = URI
::Escape
::uri_unescape
($serial);
1579 $opts .= ",serial=$serial";
1582 $opts .= ",format=$format" if $format && !$drive->{format
};
1584 foreach my $o (qw(bps bps_rd bps_wr)) {
1585 my $v = $drive->{"m$o"};
1586 $opts .= ",$o=" . int($v*1024*1024) if $v;
1589 my $cache_direct = 0;
1591 if (my $cache = $drive->{cache
}) {
1592 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1593 } elsif (!drive_is_cdrom
($drive)) {
1594 $opts .= ",cache=none";
1598 # aio native works only with O_DIRECT
1599 if (!$drive->{aio
}) {
1601 $opts .= ",aio=native";
1603 $opts .= ",aio=threads";
1607 if (!drive_is_cdrom
($drive)) {
1609 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1610 $detectzeroes = 'off';
1611 } elsif ($drive->{discard
}) {
1612 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1614 # This used to be our default with discard not being specified:
1615 $detectzeroes = 'on';
1617 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1620 my $pathinfo = $path ?
"file=$path," : '';
1622 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1625 sub print_netdevice_full
{
1626 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files) = @_;
1628 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
1630 my $device = $net->{model
};
1631 if ($net->{model
} eq 'virtio') {
1632 $device = 'virtio-net-pci';
1635 my $pciaddr = print_pci_addr
("$netid", $bridges);
1636 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1637 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1638 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1639 my $vectors = $net->{queues
} * 2 + 2;
1640 $tmpstr .= ",vectors=$vectors,mq=on";
1642 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1644 if ($use_old_bios_files) {
1646 if ($device eq 'virtio-net-pci') {
1647 $romfile = 'pxe-virtio.rom';
1648 } elsif ($device eq 'e1000') {
1649 $romfile = 'pxe-e1000.rom';
1650 } elsif ($device eq 'ne2k') {
1651 $romfile = 'pxe-ne2k_pci.rom';
1652 } elsif ($device eq 'pcnet') {
1653 $romfile = 'pxe-pcnet.rom';
1654 } elsif ($device eq 'rtl8139') {
1655 $romfile = 'pxe-rtl8139.rom';
1657 $tmpstr .= ",romfile=$romfile" if $romfile;
1663 sub print_netdev_full
{
1664 my ($vmid, $conf, $net, $netid, $hotplug) = @_;
1667 if ($netid =~ m/^net(\d+)$/) {
1671 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1673 my $ifname = "tap${vmid}i$i";
1675 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1676 die "interface name '$ifname' is too long (max 15 character)\n"
1677 if length($ifname) >= 16;
1679 my $vhostparam = '';
1680 $vhostparam = ',vhost=on' if $kernel_has_vhost_net && $net->{model
} eq 'virtio';
1682 my $vmname = $conf->{name
} || "vm$vmid";
1685 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1687 if ($net->{bridge
}) {
1688 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1690 $netdev = "type=user,id=$netid,hostname=$vmname";
1693 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1699 sub print_cpu_device
{
1700 my ($conf, $id) = @_;
1702 my $nokvm = defined($conf->{kvm
}) && $conf->{kvm
} == 0 ?
1 : 0;
1703 my $cpu = $nokvm ?
"qemu64" : "kvm64";
1704 if (my $cputype = $conf->{cpu
}) {
1705 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
1706 or die "Cannot parse cpu description: $cputype\n";
1707 $cpu = $cpuconf->{cputype
};
1711 $sockets = $conf->{sockets
} if $conf->{sockets
};
1712 my $cores = $conf->{cores
} || 1;
1714 my $current_core = ($id - 1) % $cores;
1715 my $current_socket = int(($id - $current_core)/$cores);
1717 return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
1720 sub drive_is_cdrom
{
1723 return $drive && $drive->{media
} && ($drive->{media
} eq 'cdrom');
1727 sub parse_number_sets
{
1730 foreach my $part (split(/;/, $set)) {
1731 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
1732 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
1733 push @$res, [ $1, $2 ];
1735 die "invalid range: $part\n";
1744 my $res = PVE
::JSONSchema
::parse_property_string
($numa_fmt, $data);
1745 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
1746 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
1753 return undef if !$value;
1755 my $res = PVE
::JSONSchema
::parse_property_string
($hostpci_fmt, $value);
1757 my @idlist = split(/;/, $res->{host
});
1758 delete $res->{host
};
1759 foreach my $id (@idlist) {
1760 if ($id =~ /^$PCIRE$/) {
1762 push @{$res->{pciid
}}, { id
=> $1, function
=> $2 };
1764 my $pcidevices = lspci
($1);
1765 $res->{pciid
} = $pcidevices->{$1};
1768 # should have been caught by parse_property_string already
1769 die "failed to parse PCI id: $id\n";
1775 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1779 my $res = eval { PVE
::JSONSchema
::parse_property_string
($net_fmt, $data) };
1784 if (!defined($res->{macaddr
})) {
1785 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
1786 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
1794 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
1797 sub add_random_macs
{
1798 my ($settings) = @_;
1800 foreach my $opt (keys %$settings) {
1801 next if $opt !~ m/^net(\d+)$/;
1802 my $net = parse_net
($settings->{$opt});
1804 $settings->{$opt} = print_net
($net);
1808 sub vm_is_volid_owner
{
1809 my ($storecfg, $vmid, $volid) = @_;
1811 if ($volid !~ m
|^/|) {
1813 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
1814 if ($owner && ($owner == $vmid)) {
1822 sub split_flagged_list
{
1823 my $text = shift || '';
1824 $text =~ s/[,;]/ /g;
1826 return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
1829 sub join_flagged_list
{
1830 my ($how, $lst) = @_;
1831 join $how, map { $lst->{$_} . $_ } keys %$lst;
1834 sub vmconfig_delete_pending_option
{
1835 my ($conf, $key, $force) = @_;
1837 delete $conf->{pending
}->{$key};
1838 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
1839 $pending_delete_hash->{$key} = $force ?
'!' : '';
1840 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
1843 sub vmconfig_undelete_pending_option
{
1844 my ($conf, $key) = @_;
1846 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
1847 delete $pending_delete_hash->{$key};
1849 if (%$pending_delete_hash) {
1850 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
1852 delete $conf->{pending
}->{delete};
1856 sub vmconfig_register_unused_drive
{
1857 my ($storecfg, $vmid, $conf, $drive) = @_;
1859 if (!drive_is_cdrom
($drive)) {
1860 my $volid = $drive->{file
};
1861 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
1862 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
1867 sub vmconfig_cleanup_pending
{
1870 # remove pending changes when nothing changed
1872 foreach my $opt (keys %{$conf->{pending
}}) {
1873 if (defined($conf->{$opt}) && ($conf->{pending
}->{$opt} eq $conf->{$opt})) {
1875 delete $conf->{pending
}->{$opt};
1879 my $current_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
1880 my $pending_delete_hash = {};
1881 while (my ($opt, $force) = each %$current_delete_hash) {
1882 if (defined($conf->{$opt})) {
1883 $pending_delete_hash->{$opt} = $force;
1889 if (%$pending_delete_hash) {
1890 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
1892 delete $conf->{pending
}->{delete};
1898 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
1902 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
1903 format_description
=> 'UUID',
1904 description
=> "Set SMBIOS1 UUID.",
1910 format_description
=> 'string',
1911 description
=> "Set SMBIOS1 version.",
1917 format_description
=> 'string',
1918 description
=> "Set SMBIOS1 serial number.",
1924 format_description
=> 'string',
1925 description
=> "Set SMBIOS1 manufacturer.",
1931 format_description
=> 'string',
1932 description
=> "Set SMBIOS1 product ID.",
1938 format_description
=> 'string',
1939 description
=> "Set SMBIOS1 SKU string.",
1945 format_description
=> 'string',
1946 description
=> "Set SMBIOS1 family string.",
1954 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_fmt, $data) };
1961 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
1964 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
1966 PVE
::JSONSchema
::register_format
('pve-qm-bootdisk', \
&verify_bootdisk
);
1967 sub verify_bootdisk
{
1968 my ($value, $noerr) = @_;
1970 return $value if is_valid_drivename
($value);
1972 return undef if $noerr;
1974 die "invalid boot disk '$value'\n";
1977 sub parse_watchdog
{
1980 return undef if !$value;
1982 my $res = eval { PVE
::JSONSchema
::parse_property_string
($watchdog_fmt, $value) };
1987 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
1988 sub verify_usb_device
{
1989 my ($value, $noerr) = @_;
1991 return $value if parse_usb_device
($value);
1993 return undef if $noerr;
1995 die "unable to parse usb device\n";
1998 # add JSON properties for create and set function
1999 sub json_config_properties
{
2002 foreach my $opt (keys %$confdesc) {
2003 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate';
2004 $prop->{$opt} = $confdesc->{$opt};
2011 my ($key, $value) = @_;
2013 die "unknown setting '$key'\n" if !$confdesc->{$key};
2015 my $type = $confdesc->{$key}->{type
};
2017 if (!defined($value)) {
2018 die "got undefined value\n";
2021 if ($value =~ m/[\n\r]/) {
2022 die "property contains a line feed\n";
2025 if ($type eq 'boolean') {
2026 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2027 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2028 die "type check ('boolean') failed - got '$value'\n";
2029 } elsif ($type eq 'integer') {
2030 return int($1) if $value =~ m/^(\d+)$/;
2031 die "type check ('integer') failed - got '$value'\n";
2032 } elsif ($type eq 'number') {
2033 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2034 die "type check ('number') failed - got '$value'\n";
2035 } elsif ($type eq 'string') {
2036 if (my $fmt = $confdesc->{$key}->{format
}) {
2037 PVE
::JSONSchema
::check_format
($fmt, $value);
2040 $value =~ s/^\"(.*)\"$/$1/;
2043 die "internal error"
2047 sub check_iommu_support
{
2048 #fixme : need to check IOMMU support
2049 #http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM
2059 my $conf = PVE
::QemuConfig-
>config_file($vmid);
2060 utime undef, undef, $conf;
2064 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
2066 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
2068 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2070 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2072 # only remove disks owned by this VM
2073 foreach_drive
($conf, sub {
2074 my ($ds, $drive) = @_;
2076 return if drive_is_cdrom
($drive);
2078 my $volid = $drive->{file
};
2080 return if !$volid || $volid =~ m
|^/|;
2082 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2083 return if !$path || !$owner || ($owner != $vmid);
2086 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2088 warn "Could not remove disk '$volid', check manually: $@" if $@;
2092 if ($keep_empty_config) {
2093 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
2098 # also remove unused disk
2100 my $dl = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
2103 PVE
::Storage
::foreach_volid
($dl, sub {
2104 my ($volid, $sid, $volname, $d) = @_;
2105 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2114 sub parse_vm_config
{
2115 my ($filename, $raw) = @_;
2117 return undef if !defined($raw);
2120 digest
=> Digest
::SHA
::sha1_hex
($raw),
2125 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2126 || die "got strange filename '$filename'";
2134 my @lines = split(/\n/, $raw);
2135 foreach my $line (@lines) {
2136 next if $line =~ m/^\s*$/;
2138 if ($line =~ m/^\[PENDING\]\s*$/i) {
2139 $section = 'pending';
2140 if (defined($descr)) {
2142 $conf->{description
} = $descr;
2145 $conf = $res->{$section} = {};
2148 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2150 if (defined($descr)) {
2152 $conf->{description
} = $descr;
2155 $conf = $res->{snapshots
}->{$section} = {};
2159 if ($line =~ m/^\#(.*)\s*$/) {
2160 $descr = '' if !defined($descr);
2161 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2165 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2166 $descr = '' if !defined($descr);
2167 $descr .= PVE
::Tools
::decode_text
($2);
2168 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2169 $conf->{snapstate
} = $1;
2170 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2173 $conf->{$key} = $value;
2174 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2176 if ($section eq 'pending') {
2177 $conf->{delete} = $value; # we parse this later
2179 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2181 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(\S+)\s*$/) {
2184 eval { $value = check_type
($key, $value); };
2186 warn "vm $vmid - unable to parse value of '$key' - $@";
2188 $key = 'ide2' if $key eq 'cdrom';
2189 my $fmt = $confdesc->{$key}->{format
};
2190 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2191 my $v = parse_drive
($key, $value);
2192 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2193 $v->{file
} = $volid;
2194 $value = print_drive
($vmid, $v);
2196 warn "vm $vmid - unable to parse value of '$key'\n";
2201 $conf->{$key} = $value;
2206 if (defined($descr)) {
2208 $conf->{description
} = $descr;
2210 delete $res->{snapstate
}; # just to be sure
2215 sub write_vm_config
{
2216 my ($filename, $conf) = @_;
2218 delete $conf->{snapstate
}; # just to be sure
2220 if ($conf->{cdrom
}) {
2221 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2222 $conf->{ide2
} = $conf->{cdrom
};
2223 delete $conf->{cdrom
};
2226 # we do not use 'smp' any longer
2227 if ($conf->{sockets
}) {
2228 delete $conf->{smp
};
2229 } elsif ($conf->{smp
}) {
2230 $conf->{sockets
} = $conf->{smp
};
2231 delete $conf->{cores
};
2232 delete $conf->{smp
};
2235 my $used_volids = {};
2237 my $cleanup_config = sub {
2238 my ($cref, $pending, $snapname) = @_;
2240 foreach my $key (keys %$cref) {
2241 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2242 $key eq 'snapstate' || $key eq 'pending';
2243 my $value = $cref->{$key};
2244 if ($key eq 'delete') {
2245 die "propertry 'delete' is only allowed in [PENDING]\n"
2247 # fixme: check syntax?
2250 eval { $value = check_type
($key, $value); };
2251 die "unable to parse value of '$key' - $@" if $@;
2253 $cref->{$key} = $value;
2255 if (!$snapname && is_valid_drivename
($key)) {
2256 my $drive = parse_drive
($key, $value);
2257 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2262 &$cleanup_config($conf);
2264 &$cleanup_config($conf->{pending
}, 1);
2266 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2267 die "internal error" if $snapname eq 'pending';
2268 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2271 # remove 'unusedX' settings if we re-add a volume
2272 foreach my $key (keys %$conf) {
2273 my $value = $conf->{$key};
2274 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2275 delete $conf->{$key};
2279 my $generate_raw_config = sub {
2280 my ($conf, $pending) = @_;
2284 # add description as comment to top of file
2285 if (defined(my $descr = $conf->{description
})) {
2287 foreach my $cl (split(/\n/, $descr)) {
2288 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2291 $raw .= "#\n" if $pending;
2295 foreach my $key (sort keys %$conf) {
2296 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2297 $raw .= "$key: $conf->{$key}\n";
2302 my $raw = &$generate_raw_config($conf);
2304 if (scalar(keys %{$conf->{pending
}})){
2305 $raw .= "\n[PENDING]\n";
2306 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2309 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2310 $raw .= "\n[$snapname]\n";
2311 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2321 # we use static defaults from our JSON schema configuration
2322 foreach my $key (keys %$confdesc) {
2323 if (defined(my $default = $confdesc->{$key}->{default})) {
2324 $res->{$key} = $default;
2328 my $conf = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
2329 $res->{keyboard
} = $conf->{keyboard
} if $conf->{keyboard
};
2335 my $vmlist = PVE
::Cluster
::get_vmlist
();
2337 return $res if !$vmlist || !$vmlist->{ids
};
2338 my $ids = $vmlist->{ids
};
2340 foreach my $vmid (keys %$ids) {
2341 my $d = $ids->{$vmid};
2342 next if !$d->{node
} || $d->{node
} ne $nodename;
2343 next if !$d->{type
} || $d->{type
} ne 'qemu';
2344 $res->{$vmid}->{exists} = 1;
2349 # test if VM uses local resources (to prevent migration)
2350 sub check_local_resources
{
2351 my ($conf, $noerr) = @_;
2355 $loc_res = 1 if $conf->{hostusb
}; # old syntax
2356 $loc_res = 1 if $conf->{hostpci
}; # old syntax
2358 foreach my $k (keys %$conf) {
2359 next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2360 # sockets are safe: they will recreated be on the target side post-migrate
2361 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2362 $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2365 die "VM uses local resources\n" if $loc_res && !$noerr;
2370 # check if used storages are available on all nodes (use by migrate)
2371 sub check_storage_availability
{
2372 my ($storecfg, $conf, $node) = @_;
2374 foreach_drive
($conf, sub {
2375 my ($ds, $drive) = @_;
2377 my $volid = $drive->{file
};
2380 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2383 # check if storage is available on both nodes
2384 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2385 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2389 # list nodes where all VM images are available (used by has_feature API)
2391 my ($conf, $storecfg) = @_;
2393 my $nodelist = PVE
::Cluster
::get_nodelist
();
2394 my $nodehash = { map { $_ => 1 } @$nodelist };
2395 my $nodename = PVE
::INotify
::nodename
();
2397 foreach_drive
($conf, sub {
2398 my ($ds, $drive) = @_;
2400 my $volid = $drive->{file
};
2403 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2405 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2406 if ($scfg->{disable
}) {
2408 } elsif (my $avail = $scfg->{nodes
}) {
2409 foreach my $node (keys %$nodehash) {
2410 delete $nodehash->{$node} if !$avail->{$node};
2412 } elsif (!$scfg->{shared
}) {
2413 foreach my $node (keys %$nodehash) {
2414 delete $nodehash->{$node} if $node ne $nodename
2424 my ($pidfile, $pid) = @_;
2426 my $fh = IO
::File-
>new("/proc/$pid/cmdline", "r");
2430 return undef if !$line;
2431 my @param = split(/\0/, $line);
2433 my $cmd = $param[0];
2434 return if !$cmd || ($cmd !~ m
|kvm
$| && $cmd !~ m
|qemu-system-x86_64
$|);
2436 for (my $i = 0; $i < scalar (@param); $i++) {
2439 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2440 my $p = $param[$i+1];
2441 return 1 if $p && ($p eq $pidfile);
2450 my ($vmid, $nocheck, $node) = @_;
2452 my $filename = PVE
::QemuConfig-
>config_file($vmid, $node);
2454 die "unable to find configuration file for VM $vmid - no such machine\n"
2455 if !$nocheck && ! -f
$filename;
2457 my $pidfile = pidfile_name
($vmid);
2459 if (my $fd = IO
::File-
>new("<$pidfile")) {
2464 my $mtime = $st->mtime;
2465 if ($mtime > time()) {
2466 warn "file '$filename' modified in future\n";
2469 if ($line =~ m/^(\d+)$/) {
2471 if (check_cmdline
($pidfile, $pid)) {
2472 if (my $pinfo = PVE
::ProcFSTools
::check_process_running
($pid)) {
2484 my $vzlist = config_list
();
2486 my $fd = IO
::Dir-
>new($var_run_tmpdir) || return $vzlist;
2488 while (defined(my $de = $fd->read)) {
2489 next if $de !~ m/^(\d+)\.pid$/;
2491 next if !defined($vzlist->{$vmid});
2492 if (my $pid = check_running
($vmid)) {
2493 $vzlist->{$vmid}->{pid
} = $pid;
2501 my ($storecfg, $conf) = @_;
2503 my $bootdisk = $conf->{bootdisk
};
2504 return undef if !$bootdisk;
2505 return undef if !is_valid_drivename
($bootdisk);
2507 return undef if !$conf->{$bootdisk};
2509 my $drive = parse_drive
($bootdisk, $conf->{$bootdisk});
2510 return undef if !defined($drive);
2512 return undef if drive_is_cdrom
($drive);
2514 my $volid = $drive->{file
};
2515 return undef if !$volid;
2517 return $drive->{size
};
2520 my $last_proc_pid_stat;
2522 # get VM status information
2523 # This must be fast and should not block ($full == false)
2524 # We only query KVM using QMP if $full == true (this can be slow)
2526 my ($opt_vmid, $full) = @_;
2530 my $storecfg = PVE
::Storage
::config
();
2532 my $list = vzlist
();
2533 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2535 my $cpucount = $cpuinfo->{cpus
} || 1;
2537 foreach my $vmid (keys %$list) {
2538 next if $opt_vmid && ($vmid ne $opt_vmid);
2540 my $cfspath = PVE
::QemuConfig-
>cfs_config_path($vmid);
2541 my $conf = PVE
::Cluster
::cfs_read_file
($cfspath) || {};
2544 $d->{pid
} = $list->{$vmid}->{pid
};
2546 # fixme: better status?
2547 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
2549 my $size = disksize
($storecfg, $conf);
2550 if (defined($size)) {
2551 $d->{disk
} = 0; # no info available
2552 $d->{maxdisk
} = $size;
2558 $d->{cpus
} = ($conf->{sockets
} || 1) * ($conf->{cores
} || 1);
2559 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
2560 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
2562 $d->{name
} = $conf->{name
} || "VM $vmid";
2563 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024) : 0;
2565 if ($conf->{balloon
}) {
2566 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
2567 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
} : 1000;
2578 $d->{diskwrite
} = 0;
2580 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
2585 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
2586 foreach my $dev (keys %$netdev) {
2587 next if $dev !~ m/^tap([1-9]\d*)i/;
2589 my $d = $res->{$vmid};
2592 $d->{netout
} += $netdev->{$dev}->{receive
};
2593 $d->{netin
} += $netdev->{$dev}->{transmit
};
2596 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
2597 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
2602 my $ctime = gettimeofday
;
2604 foreach my $vmid (keys %$list) {
2606 my $d = $res->{$vmid};
2607 my $pid = $d->{pid
};
2610 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
2611 next if !$pstat; # not running
2613 my $used = $pstat->{utime} + $pstat->{stime
};
2615 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
2617 if ($pstat->{vsize
}) {
2618 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
2621 my $old = $last_proc_pid_stat->{$pid};
2623 $last_proc_pid_stat->{$pid} = {
2631 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
2633 if ($dtime > 1000) {
2634 my $dutime = $used - $old->{used
};
2636 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
2637 $last_proc_pid_stat->{$pid} = {
2643 $d->{cpu
} = $old->{cpu
};
2647 return $res if !$full;
2649 my $qmpclient = PVE
::QMPClient-
>new();
2651 my $ballooncb = sub {
2652 my ($vmid, $resp) = @_;
2654 my $info = $resp->{'return'};
2655 return if !$info->{max_mem
};
2657 my $d = $res->{$vmid};
2659 # use memory assigned to VM
2660 $d->{maxmem
} = $info->{max_mem
};
2661 $d->{balloon
} = $info->{actual
};
2663 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
2664 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
2665 $d->{freemem
} = $info->{free_mem
};
2668 $d->{ballooninfo
} = $info;
2671 my $blockstatscb = sub {
2672 my ($vmid, $resp) = @_;
2673 my $data = $resp->{'return'} || [];
2674 my $totalrdbytes = 0;
2675 my $totalwrbytes = 0;
2677 for my $blockstat (@$data) {
2678 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
2679 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
2681 $blockstat->{device
} =~ s/drive-//;
2682 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
2684 $res->{$vmid}->{diskread
} = $totalrdbytes;
2685 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
2688 my $statuscb = sub {
2689 my ($vmid, $resp) = @_;
2691 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
2692 # this fails if ballon driver is not loaded, so this must be
2693 # the last commnand (following command are aborted if this fails).
2694 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
2696 my $status = 'unknown';
2697 if (!defined($status = $resp->{'return'}->{status
})) {
2698 warn "unable to get VM status\n";
2702 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
2705 foreach my $vmid (keys %$list) {
2706 next if $opt_vmid && ($vmid ne $opt_vmid);
2707 next if !$res->{$vmid}->{pid
}; # not running
2708 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
2711 $qmpclient->queue_execute(undef, 2);
2713 foreach my $vmid (keys %$list) {
2714 next if $opt_vmid && ($vmid ne $opt_vmid);
2715 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
2722 my ($conf, $func, @param) = @_;
2724 foreach my $ds (valid_drive_names
()) {
2725 next if !defined($conf->{$ds});
2727 my $drive = parse_drive
($ds, $conf->{$ds});
2730 &$func($ds, $drive, @param);
2735 my ($conf, $func, @param) = @_;
2739 my $test_volid = sub {
2740 my ($volid, $is_cdrom) = @_;
2744 $volhash->{$volid} = $is_cdrom || 0;
2747 foreach_drive
($conf, sub {
2748 my ($ds, $drive) = @_;
2749 &$test_volid($drive->{file
}, drive_is_cdrom
($drive));
2752 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2753 my $snap = $conf->{snapshots
}->{$snapname};
2754 &$test_volid($snap->{vmstate
}, 0);
2755 foreach_drive
($snap, sub {
2756 my ($ds, $drive) = @_;
2757 &$test_volid($drive->{file
}, drive_is_cdrom
($drive));
2761 foreach my $volid (keys %$volhash) {
2762 &$func($volid, $volhash->{$volid}, @param);
2766 sub vga_conf_has_spice
{
2769 return 0 if !$vga || $vga !~ m/^qxl([234])?$/;
2774 sub config_to_command
{
2775 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
2778 my $globalFlags = [];
2779 my $machineFlags = [];
2785 my $kvmver = kvm_user_version
();
2786 my $vernum = 0; # unknown
2787 my $ostype = $conf->{ostype
};
2788 my $winversion = windows_version
($ostype);
2790 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
2791 $vernum = $1*1000000+$2*1000;
2792 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
2793 $vernum = $1*1000000+$2*1000+$3;
2796 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
2798 my $have_ovz = -f
'/proc/vz/vestat';
2800 my $q35 = machine_type_is_q35
($conf);
2801 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
2802 my $machine_type = $forcemachine || $conf->{machine
};
2803 my $use_old_bios_files = undef;
2804 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
2806 my $cpuunits = defined($conf->{cpuunits
}) ?
2807 $conf->{cpuunits
} : $defaults->{cpuunits
};
2809 push @$cmd, '/usr/bin/kvm';
2811 push @$cmd, '-id', $vmid;
2815 my $qmpsocket = qmp_socket
($vmid);
2816 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
2817 push @$cmd, '-mon', "chardev=qmp,mode=control";
2820 push @$cmd, '-pidfile' , pidfile_name
($vmid);
2822 push @$cmd, '-daemonize';
2824 if ($conf->{smbios1
}) {
2825 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
2828 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
2831 # prefer the OVMF_CODE variant
2832 if (-f
$OVMF_CODE) {
2833 $ovmfbase = $OVMF_CODE;
2834 } elsif (-f
$OVMF_IMG) {
2835 $ovmfbase = $OVMF_IMG;
2838 die "no uefi base img found\n" if !$ovmfbase;
2839 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$ovmfbase";
2841 if (defined($conf->{efidisk0
}) && ($ovmfbase eq $OVMF_CODE)) {
2842 my $d = PVE
::JSONSchema
::parse_property_string
($efidisk_fmt, $conf->{efidisk0
});
2843 my $format = $d->{format
} // 'raw';
2845 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
2847 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
2848 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2849 $format = qemu_img_format
($scfg, $volname);
2854 push @$cmd, '-drive', "if=pflash,unit=1,id=drive-efidisk0,format=$format,file=$path";
2855 } elsif ($ovmfbase eq $OVMF_CODE) {
2856 warn "using uefi without permanent efivars disk\n";
2857 my $ovmfvar_dst = "/tmp/$vmid-ovmf.fd";
2858 PVE
::Tools
::file_copy
($OVMF_VARS, $ovmfvar_dst, 256*1024);
2859 push @$cmd, '-drive', "if=pflash,unit=1,format=raw,file=$ovmfvar_dst";
2861 # if the base img is not OVMF_CODE, we do not have to bother
2862 # to create/use a vars image, since it will not be used anyway
2863 # this can only happen if someone manually deletes the OVMF_CODE image
2864 # or has an old pve-qemu-kvm version installed.
2865 # both should not happen, but we ignore it here
2870 # add usb controllers
2871 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $q35, $usbdesc->{format
}, $MAX_USB_DEVICES);
2872 push @$devices, @usbcontrollers if @usbcontrollers;
2873 my $vga = $conf->{vga
};
2875 my $qxlnum = vga_conf_has_spice
($vga);
2876 $vga = 'qxl' if $qxlnum;
2879 $vga = $winversion >= 6 ?
'std' : 'cirrus';
2882 # enable absolute mouse coordinates (needed by vnc)
2884 if (defined($conf->{tablet
})) {
2885 $tablet = $conf->{tablet
};
2887 $tablet = $defaults->{tablet
};
2888 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
2889 $tablet = 0 if $vga =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
2892 push @$devices, '-device', print_tabletdevice_full
($conf) if $tablet;
2895 my $gpu_passthrough;
2898 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
2899 my $d = parse_hostpci
($conf->{"hostpci$i"});
2902 my $pcie = $d->{pcie
};
2904 die "q35 machine model is not enabled" if !$q35;
2905 $pciaddr = print_pcie_addr
("hostpci$i");
2907 $pciaddr = print_pci_addr
("hostpci$i", $bridges);
2910 my $rombar = defined($d->{rombar
}) && !$d->{rombar
} ?
',rombar=0' : '';
2912 if ($d->{'x-vga'}) {
2913 $xvga = ',x-vga=on';
2916 $gpu_passthrough = 1;
2918 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
2922 my $pcidevices = $d->{pciid
};
2923 my $multifunction = 1 if @$pcidevices > 1;
2926 foreach my $pcidevice (@$pcidevices) {
2928 my $id = "hostpci$i";
2929 $id .= ".$j" if $multifunction;
2930 my $addr = $pciaddr;
2931 $addr .= ".$j" if $multifunction;
2932 my $devicestr = "vfio-pci,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
2935 $devicestr .= "$rombar$xvga";
2936 $devicestr .= ",multifunction=on" if $multifunction;
2939 push @$devices, '-device', $devicestr;
2945 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES);
2946 push @$devices, @usbdevices if @usbdevices;
2948 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
2949 if (my $path = $conf->{"serial$i"}) {
2950 if ($path eq 'socket') {
2951 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
2952 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
2953 push @$devices, '-device', "isa-serial,chardev=serial$i";
2955 die "no such serial device\n" if ! -c
$path;
2956 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
2957 push @$devices, '-device', "isa-serial,chardev=serial$i";
2963 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
2964 if (my $path = $conf->{"parallel$i"}) {
2965 die "no such parallel device\n" if ! -c
$path;
2966 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
2967 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
2968 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
2972 my $vmname = $conf->{name
} || "vm$vmid";
2974 push @$cmd, '-name', $vmname;
2977 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
2978 $sockets = $conf->{sockets
} if $conf->{sockets
};
2980 my $cores = $conf->{cores
} || 1;
2982 my $maxcpus = $sockets * $cores;
2984 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
2986 my $allowed_vcpus = $cpuinfo->{cpus
};
2988 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
2989 if ($allowed_vcpus < $maxcpus);
2991 if($hotplug_features->{cpu
} && qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 7)) {
2993 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
2994 for (my $i = 2; $i <= $vcpus; $i++) {
2995 my $cpustr = print_cpu_device
($conf,$i);
2996 push @$cmd, '-device', $cpustr;
3001 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3003 push @$cmd, '-nodefaults';
3005 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3007 my $bootindex_hash = {};
3009 foreach my $o (split(//, $bootorder)) {
3010 $bootindex_hash->{$o} = $i*100;
3014 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3016 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3018 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3020 push @$cmd, '-vga', $vga if $vga && $vga !~ m/^serial\d+$/; # for kvm 77 and later
3022 if ($vga && $vga !~ m/^serial\d+$/ && $vga ne 'none'){
3023 my $socket = vnc_socket
($vmid);
3024 push @$cmd, '-vnc', "unix:$socket,x509,password";
3026 push @$cmd, '-nographic';
3030 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3032 my $nokvm = defined($conf->{kvm
}) && $conf->{kvm
} == 0 ?
1 : 0;
3033 my $useLocaltime = $conf->{localtime};
3035 if ($winversion >= 5) { # windows
3036 $useLocaltime = 1 if !defined($conf->{localtime});
3038 # use time drift fix when acpi is enabled
3039 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3040 $tdf = 1 if !defined($conf->{tdf
});
3044 if ($winversion >= 6) {
3045 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3046 push @$cmd, '-no-hpet';
3049 push @$rtcFlags, 'driftfix=slew' if $tdf;
3052 push @$machineFlags, 'accel=tcg';
3054 die "No accelerator found!\n" if !$cpuinfo->{hvm
};
3057 if ($machine_type) {
3058 push @$machineFlags, "type=${machine_type}";
3061 if ($conf->{startdate
}) {
3062 push @$rtcFlags, "base=$conf->{startdate}";
3063 } elsif ($useLocaltime) {
3064 push @$rtcFlags, 'base=localtime';
3067 my $cpu = $nokvm ?
"qemu64" : "kvm64";
3068 if (my $cputype = $conf->{cpu
}) {
3069 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
3070 or die "Cannot parse cpu description: $cputype\n";
3071 $cpu = $cpuconf->{cputype
};
3072 $kvm_off = 1 if $cpuconf->{hidden
};
3075 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64';
3077 push @$cpuFlags , '-x2apic'
3078 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3080 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3082 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3084 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3086 push @$cpuFlags , '+kvm_pv_unhalt' if !$nokvm;
3087 push @$cpuFlags , '+kvm_pv_eoi' if !$nokvm;
3090 add_hyperv_enlighments
($cpuFlags, $winversion, $machine_type, $kvmver, $nokvm, $conf->{bios
}, $gpu_passthrough);
3092 push @$cpuFlags, 'enforce' if $cpu ne 'host' && !$nokvm;
3094 push @$cpuFlags, 'kvm=off' if $kvm_off;
3096 my $cpu_vendor = $cpu_vendor_list->{$cpu} ||
3097 die "internal error"; # should not happen
3099 push @$cpuFlags, "vendor=${cpu_vendor}"
3100 if $cpu_vendor ne 'default';
3102 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3104 push @$cmd, '-cpu', $cpu;
3106 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3108 push @$cmd, '-S' if $conf->{freeze
};
3110 # set keyboard layout
3111 my $kb = $conf->{keyboard
} || $defaults->{keyboard
};
3112 push @$cmd, '-k', $kb if $kb;
3115 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3116 #push @$cmd, '-soundhw', 'es1370';
3117 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3119 if($conf->{agent
}) {
3120 my $qgasocket = qmp_socket
($vmid, 1);
3121 my $pciaddr = print_pci_addr
("qga0", $bridges);
3122 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3123 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3124 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3132 for(my $i = 1; $i < $qxlnum; $i++){
3133 my $pciaddr = print_pci_addr
("vga$i", $bridges);
3134 push @$cmd, '-device', "qxl,id=vga$i,ram_size=67108864,vram_size=33554432$pciaddr";
3137 # assume other OS works like Linux
3138 push @$cmd, '-global', 'qxl-vga.ram_size=134217728';
3139 push @$cmd, '-global', 'qxl-vga.vram_size=67108864';
3143 my $pciaddr = print_pci_addr
("spice", $bridges);
3145 my $nodename = PVE
::INotify
::nodename
();
3146 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3147 $spice_port = PVE
::Tools
::next_spice_port
($pfamily);
3149 push @$devices, '-spice', "tls-port=${spice_port},addr=localhost,tls-ciphers=DES-CBC3-SHA,seamless-migration=on";
3151 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3152 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3153 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3156 # enable balloon by default, unless explicitly disabled
3157 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3158 $pciaddr = print_pci_addr
("balloon0", $bridges);
3159 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3162 if ($conf->{watchdog
}) {
3163 my $wdopts = parse_watchdog
($conf->{watchdog
});
3164 $pciaddr = print_pci_addr
("watchdog", $bridges);
3165 my $watchdog = $wdopts->{model
} || 'i6300esb';
3166 push @$devices, '-device', "$watchdog$pciaddr";
3167 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3171 my $scsicontroller = {};
3172 my $ahcicontroller = {};
3173 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3175 # Add iscsi initiator name if available
3176 if (my $initiator = get_initiator_name
()) {
3177 push @$devices, '-iscsi', "initiator-name=$initiator";
3180 foreach_drive
($conf, sub {
3181 my ($ds, $drive) = @_;
3183 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3184 push @$vollist, $drive->{file
};
3187 $use_virtio = 1 if $ds =~ m/^virtio/;
3189 if (drive_is_cdrom
($drive)) {
3190 if ($bootindex_hash->{d
}) {
3191 $drive->{bootindex
} = $bootindex_hash->{d
};
3192 $bootindex_hash->{d
} += 1;
3195 if ($bootindex_hash->{c
}) {
3196 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3197 $bootindex_hash->{c
} += 1;
3201 if($drive->{interface
} eq 'virtio'){
3202 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3205 if ($drive->{interface
} eq 'scsi') {
3207 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3209 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges);
3210 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3213 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3214 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3215 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3216 } elsif ($drive->{iothread
}) {
3217 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3221 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3222 $queues = ",num_queues=$drive->{queues}";
3225 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3226 $scsicontroller->{$controller}=1;
3229 if ($drive->{interface
} eq 'sata') {
3230 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3231 $pciaddr = print_pci_addr
("ahci$controller", $bridges);
3232 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3233 $ahcicontroller->{$controller}=1;
3236 if ($drive->{interface
} eq 'efidisk') {
3237 # this will be added somewhere else
3241 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3242 push @$devices, '-drive',$drive_cmd;
3243 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges);
3246 for (my $i = 0; $i < $MAX_NETS; $i++) {
3247 next if !$conf->{"net$i"};
3248 my $d = parse_net
($conf->{"net$i"});
3251 $use_virtio = 1 if $d->{model
} eq 'virtio';
3253 if ($bootindex_hash->{n
}) {
3254 $d->{bootindex
} = $bootindex_hash->{n
};
3255 $bootindex_hash->{n
} += 1;
3258 my $netdevfull = print_netdev_full
($vmid,$conf,$d,"net$i");
3259 push @$devices, '-netdev', $netdevfull;
3261 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files);
3262 push @$devices, '-device', $netdevicefull;
3267 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3272 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3274 while (my ($k, $v) = each %$bridges) {
3275 $pciaddr = print_pci_addr
("pci.$k");
3276 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3281 if ($conf->{args
}) {
3282 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3286 push @$cmd, @$devices;
3287 push @$cmd, '-rtc', join(',', @$rtcFlags)
3288 if scalar(@$rtcFlags);
3289 push @$cmd, '-machine', join(',', @$machineFlags)
3290 if scalar(@$machineFlags);
3291 push @$cmd, '-global', join(',', @$globalFlags)
3292 if scalar(@$globalFlags);
3294 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3299 return "${var_run_tmpdir}/$vmid.vnc";
3305 my $res = vm_mon_cmd
($vmid, 'query-spice');
3307 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3311 my ($vmid, $qga) = @_;
3312 my $sockettype = $qga ?
'qga' : 'qmp';
3313 return "${var_run_tmpdir}/$vmid.$sockettype";
3318 return "${var_run_tmpdir}/$vmid.pid";
3321 sub vm_devices_list
{
3324 my $res = vm_mon_cmd
($vmid, 'query-pci');
3326 foreach my $pcibus (@$res) {
3327 foreach my $device (@{$pcibus->{devices
}}) {
3328 next if !$device->{'qdev_id'};
3329 if ($device->{'pci_bridge'}) {
3330 $devices->{$device->{'qdev_id'}} = 1;
3331 foreach my $bridge_device (@{$device->{'pci_bridge'}->{devices
}}) {
3332 next if !$bridge_device->{'qdev_id'};
3333 $devices->{$bridge_device->{'qdev_id'}} = 1;
3334 $devices->{$device->{'qdev_id'}}++;
3337 $devices->{$device->{'qdev_id'}} = 1;
3342 my $resblock = vm_mon_cmd
($vmid, 'query-block');
3343 foreach my $block (@$resblock) {
3344 if($block->{device
} =~ m/^drive-(\S+)/){
3349 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
3350 foreach my $mice (@$resmice) {
3351 if ($mice->{name
} eq 'QEMU HID Tablet') {
3352 $devices->{tablet
} = 1;
3357 # for usb devices there is no query-usb
3358 # but we can iterate over the entries in
3359 # qom-list path=/machine/peripheral
3360 my $resperipheral = vm_mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3361 foreach my $per (@$resperipheral) {
3362 if ($per->{name
} =~ m/^usb\d+$/) {
3363 $devices->{$per->{name
}} = 1;
3371 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
3373 my $q35 = machine_type_is_q35
($conf);
3375 my $devices_list = vm_devices_list
($vmid);
3376 return 1 if defined($devices_list->{$deviceid});
3378 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid); # add PCI bridge if we need it for the device
3380 if ($deviceid eq 'tablet') {
3382 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf));
3384 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3386 die "usb hotplug currently not reliable\n";
3387 # since we can't reliably hot unplug all added usb devices
3388 # and usb passthrough disables live migration
3389 # we disable usb hotplugging for now
3390 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
3392 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3394 qemu_iothread_add
($vmid, $deviceid, $device);
3396 qemu_driveadd
($storecfg, $vmid, $device);
3397 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3399 qemu_deviceadd
($vmid, $devicefull);
3400 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3402 eval { qemu_drivedel
($vmid, $deviceid); };
3407 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3410 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
3411 my $pciaddr = print_pci_addr
($deviceid);
3412 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
3414 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
3416 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
3417 qemu_iothread_add
($vmid, $deviceid, $device);
3418 $devicefull .= ",iothread=iothread-$deviceid";
3421 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
3422 $devicefull .= ",num_queues=$device->{queues}";
3425 qemu_deviceadd
($vmid, $devicefull);
3426 qemu_deviceaddverify
($vmid, $deviceid);
3428 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3430 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device);
3431 qemu_driveadd
($storecfg, $vmid, $device);
3433 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3434 eval { qemu_deviceadd
($vmid, $devicefull); };
3436 eval { qemu_drivedel
($vmid, $deviceid); };
3441 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3443 return undef if !qemu_netdevadd
($vmid, $conf, $device, $deviceid);
3445 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
3446 my $use_old_bios_files = undef;
3447 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3449 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files);
3450 qemu_deviceadd
($vmid, $netdevicefull);
3451 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3453 eval { qemu_netdevdel
($vmid, $deviceid); };
3458 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
3461 my $pciaddr = print_pci_addr
($deviceid);
3462 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
3464 qemu_deviceadd
($vmid, $devicefull);
3465 qemu_deviceaddverify
($vmid, $deviceid);
3468 die "can't hotplug device '$deviceid'\n";
3474 # fixme: this should raise exceptions on error!
3475 sub vm_deviceunplug
{
3476 my ($vmid, $conf, $deviceid) = @_;
3478 my $devices_list = vm_devices_list
($vmid);
3479 return 1 if !defined($devices_list->{$deviceid});
3481 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
3483 if ($deviceid eq 'tablet') {
3485 qemu_devicedel
($vmid, $deviceid);
3487 } elsif ($deviceid =~ m/^usb\d+$/) {
3489 die "usb hotplug currently not reliable\n";
3490 # when unplugging usb devices this way,
3491 # there may be remaining usb controllers/hubs
3492 # so we disable it for now
3493 qemu_devicedel
($vmid, $deviceid);
3494 qemu_devicedelverify
($vmid, $deviceid);
3496 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3498 qemu_devicedel
($vmid, $deviceid);
3499 qemu_devicedelverify
($vmid, $deviceid);
3500 qemu_drivedel
($vmid, $deviceid);
3501 qemu_iothread_del
($conf, $vmid, $deviceid);
3503 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3505 qemu_devicedel
($vmid, $deviceid);
3506 qemu_devicedelverify
($vmid, $deviceid);
3507 qemu_iothread_del
($conf, $vmid, $deviceid);
3509 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3511 #qemu 2.3 segfault on drive_del with virtioscsi + iothread
3512 my $device = parse_drive
($deviceid, $conf->{$deviceid});
3513 die "virtioscsi with iothread is not hot-unplugglable currently" if $device->{iothread
};
3515 qemu_devicedel
($vmid, $deviceid);
3516 qemu_drivedel
($vmid, $deviceid);
3517 qemu_deletescsihw
($conf, $vmid, $deviceid);
3519 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3521 qemu_devicedel
($vmid, $deviceid);
3522 qemu_devicedelverify
($vmid, $deviceid);
3523 qemu_netdevdel
($vmid, $deviceid);
3526 die "can't unplug device '$deviceid'\n";
3532 sub qemu_deviceadd
{
3533 my ($vmid, $devicefull) = @_;
3535 $devicefull = "driver=".$devicefull;
3536 my %options = split(/[=,]/, $devicefull);
3538 vm_mon_cmd
($vmid, "device_add" , %options);
3541 sub qemu_devicedel
{
3542 my ($vmid, $deviceid) = @_;
3544 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
3547 sub qemu_iothread_add
{
3548 my($vmid, $deviceid, $device) = @_;
3550 if ($device->{iothread
}) {
3551 my $iothreads = vm_iothreads_list
($vmid);
3552 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
3556 sub qemu_iothread_del
{
3557 my($conf, $vmid, $deviceid) = @_;
3559 my $device = parse_drive
($deviceid, $conf->{$deviceid});
3560 if ($device->{iothread
}) {
3561 my $iothreads = vm_iothreads_list
($vmid);
3562 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
3566 sub qemu_objectadd
{
3567 my($vmid, $objectid, $qomtype) = @_;
3569 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
3574 sub qemu_objectdel
{
3575 my($vmid, $objectid) = @_;
3577 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
3583 my ($storecfg, $vmid, $device) = @_;
3585 my $drive = print_drive_full
($storecfg, $vmid, $device);
3586 $drive =~ s/\\/\\\\/g;
3587 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
3589 # If the command succeeds qemu prints: "OK
"
3590 return 1 if $ret =~ m/OK/s;
3592 die "adding drive failed
: $ret\n";
3596 my($vmid, $deviceid) = @_;
3598 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
3601 return 1 if $ret eq "";
3603 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
3604 return 1 if $ret =~ m/Device \'.*?\' not found/s;
3606 die "deleting drive
$deviceid failed
: $ret\n";
3609 sub qemu_deviceaddverify {
3610 my ($vmid, $deviceid) = @_;
3612 for (my $i = 0; $i <= 5; $i++) {
3613 my $devices_list = vm_devices_list($vmid);
3614 return 1 if defined($devices_list->{$deviceid});
3618 die "error on hotplug device
'$deviceid'\n";
3622 sub qemu_devicedelverify {
3623 my ($vmid, $deviceid) = @_;
3625 # need to verify that the device is correctly removed as device_del
3626 # is async and empty return is not reliable
3628 for (my $i = 0; $i <= 5; $i++) {
3629 my $devices_list = vm_devices_list($vmid);
3630 return 1 if !defined($devices_list->{$deviceid});
3634 die "error on hot-unplugging device
'$deviceid'\n";
3637 sub qemu_findorcreatescsihw {
3638 my ($storecfg, $conf, $vmid, $device) = @_;
3640 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3642 my $scsihwid="$controller_prefix$controller";
3643 my $devices_list = vm_devices_list($vmid);
3645 if(!defined($devices_list->{$scsihwid})) {
3646 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device);
3652 sub qemu_deletescsihw {
3653 my ($conf, $vmid, $opt) = @_;
3655 my $device = parse_drive($opt, $conf->{$opt});
3657 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
3658 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
3662 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3664 my $devices_list = vm_devices_list($vmid);
3665 foreach my $opt (keys %{$devices_list}) {
3666 if (PVE::QemuServer::is_valid_drivename($opt)) {
3667 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
3668 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
3674 my $scsihwid="scsihw
$controller";
3676 vm_deviceunplug($vmid, $conf, $scsihwid);
3681 sub qemu_add_pci_bridge {
3682 my ($storecfg, $conf, $vmid, $device) = @_;
3688 print_pci_addr($device, $bridges);
3690 while (my ($k, $v) = each %$bridges) {
3693 return 1 if !defined($bridgeid) || $bridgeid < 1;
3695 my $bridge = "pci
.$bridgeid";
3696 my $devices_list = vm_devices_list($vmid);
3698 if (!defined($devices_list->{$bridge})) {
3699 vm_deviceplug($storecfg, $conf, $vmid, $bridge);
3705 sub qemu_set_link_status {
3706 my ($vmid, $device, $up) = @_;
3708 vm_mon_cmd($vmid, "set_link
", name => $device,
3709 up => $up ? JSON::true : JSON::false);
3712 sub qemu_netdevadd {
3713 my ($vmid, $conf, $device, $deviceid) = @_;
3715 my $netdev = print_netdev_full($vmid, $conf, $device, $deviceid, 1);
3716 my %options = split(/[=,]/, $netdev);
3718 vm_mon_cmd($vmid, "netdev_add
", %options);
3722 sub qemu_netdevdel {
3723 my ($vmid, $deviceid) = @_;
3725 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
3728 sub qemu_usb_hotplug {
3729 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
3733 # remove the old one first
3734 vm_deviceunplug($vmid, $conf, $deviceid);
3736 # check if xhci controller is necessary and available
3737 if ($device->{usb3}) {
3739 my $devicelist = vm_devices_list($vmid);
3741 if (!$devicelist->{xhci}) {
3742 my $pciaddr = print_pci_addr("xhci
");
3743 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
3746 my $d = parse_usb_device($device->{host});
3747 $d->{usb3} = $device->{usb3};
3750 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d);
3753 sub qemu_cpu_hotplug {
3754 my ($vmid, $conf, $vcpus) = @_;
3756 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
3759 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
3760 $sockets = $conf->{sockets} if $conf->{sockets};
3761 my $cores = $conf->{cores} || 1;
3762 my $maxcpus = $sockets * $cores;
3764 $vcpus = $maxcpus if !$vcpus;
3766 die "you can
't add more vcpus than maxcpus\n"
3767 if $vcpus > $maxcpus;
3769 my $currentvcpus = $conf->{vcpus} || $maxcpus;
3771 if ($vcpus < $currentvcpus) {
3773 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
3775 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
3776 qemu_devicedel($vmid, "cpu$i");
3778 my $currentrunningvcpus = undef;
3780 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
3781 last if scalar(@{$currentrunningvcpus}) == $i-1;
3782 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
3786 #update conf after each succesfull cpu unplug
3787 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
3788 PVE::QemuConfig->write_config($vmid, $conf);
3791 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
3797 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
3798 die "vcpus in running vm does not match its configuration\n"
3799 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
3801 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
3803 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
3804 my $cpustr = print_cpu_device($conf, $i);
3805 qemu_deviceadd($vmid, $cpustr);
3808 my $currentrunningvcpus = undef;
3810 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
3811 last if scalar(@{$currentrunningvcpus}) == $i;
3812 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
3816 #update conf after each succesfull cpu hotplug
3817 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
3818 PVE::QemuConfig->write_config($vmid, $conf);
3822 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
3823 vm_mon_cmd($vmid, "cpu-add", id => int($i));
3828 sub qemu_block_set_io_throttle {
3829 my ($vmid, $deviceid,
3830 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
3831 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
3832 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
3833 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
3835 return if !check_running($vmid) ;
3837 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
3839 bps_rd => int($bps_rd),
3840 bps_wr => int($bps_wr),
3842 iops_rd => int($iops_rd),
3843 iops_wr => int($iops_wr),
3844 bps_max => int($bps_max),
3845 bps_rd_max => int($bps_rd_max),
3846 bps_wr_max => int($bps_wr_max),
3847 iops_max => int($iops_max),
3848 iops_rd_max => int($iops_rd_max),
3849 iops_wr_max => int($iops_wr_max),
3850 bps_max_length => int($bps_max_length),
3851 bps_rd_max_length => int($bps_rd_max_length),
3852 bps_wr_max_length => int($bps_wr_max_length),
3853 iops_max_length => int($iops_max_length),
3854 iops_rd_max_length => int($iops_rd_max_length),
3855 iops_wr_max_length => int($iops_wr_max_length),
3860 # old code, only used to shutdown old VM after update
3862 my ($fh, $timeout) = @_;
3864 my $sel = new IO::Select;
3871 while (scalar (@ready = $sel->can_read($timeout))) {
3873 if ($count = $fh->sysread($buf, 8192)) {
3874 if ($buf =~ /^(.*)\(qemu\) $/s) {
3881 if (!defined($count)) {
3888 die "monitor read timeout\n" if !scalar(@ready);
3893 # old code, only used to shutdown old VM after update
3894 sub vm_monitor_command {
3895 my ($vmid, $cmdstr, $nocheck) = @_;
3900 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
3902 my $sname = "${var_run_tmpdir}/$vmid.mon";
3904 my $sock = IO::Socket::UNIX->new( Peer => $sname ) ||
3905 die "unable to connect to VM $vmid socket - $!\n";
3909 # hack: migrate sometime blocks the monitor (when migrate_downtime
3911 if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
3912 $timeout = 60*60; # 1 hour
3916 my $data = __read_avail($sock, $timeout);
3918 if ($data !~ m/^QEMU\s+(\S+)\s+monitor\s/) {
3919 die "got unexpected qemu monitor banner\n";
3922 my $sel = new IO::Select;
3925 if (!scalar(my @ready = $sel->can_write($timeout))) {
3926 die "monitor write error - timeout";
3929 my $fullcmd = "$cmdstr\r";
3931 # syslog('info
', "VM $vmid monitor command: $cmdstr");
3934 if (!($b = $sock->syswrite($fullcmd)) || ($b != length($fullcmd))) {
3935 die "monitor write error - $!";
3938 return if ($cmdstr eq 'q
') || ($cmdstr eq 'quit
');
3942 if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
3943 $timeout = 60*60; # 1 hour
3944 } elsif ($cmdstr =~ m/^(eject|change)/) {
3945 $timeout = 60; # note: cdrom mount command is slow
3947 if ($res = __read_avail($sock, $timeout)) {
3949 my @lines = split("\r?\n", $res);
3951 shift @lines if $lines[0] !~ m/^unknown command/; # skip echo
3953 $res = join("\n", @lines);
3961 syslog("err", "VM $vmid monitor command failed - $err");
3968 sub qemu_block_resize {
3969 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
3971 my $running = check_running($vmid);
3973 return if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
3975 return if !$running;
3977 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
3981 sub qemu_volume_snapshot {
3982 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
3984 my $running = check_running($vmid);
3986 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
3987 vm_mon_cmd($vmid, "snapshot-drive", device => $deviceid, name => $snap);
3989 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
3993 sub qemu_volume_snapshot_delete {
3994 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
3996 my $running = check_running($vmid);
3998 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
3999 vm_mon_cmd($vmid, "delete-drive-snapshot", device => $deviceid, name => $snap);
4001 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4005 sub set_migration_caps {
4011 "auto-converge" => 1,
4013 "x-rdma-pin-all" => 0,
4018 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4020 for my $supported_capability (@$supported_capabilities) {
4022 capability => $supported_capability->{capability},
4023 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4027 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4030 my $fast_plug_option = {
4040 # hotplug changes in [PENDING]
4041 # $selection hash can be used to only apply specified options, for
4042 # example: { cores => 1 } (only apply changed 'cores
')
4043 # $errors ref is used to return error messages
4044 sub vmconfig_hotplug_pending {
4045 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4047 my $defaults = load_defaults();
4049 # commit values which do not have any impact on running VM first
4050 # Note: those option cannot raise errors, we we do not care about
4051 # $selection and always apply them.
4053 my $add_error = sub {
4054 my ($opt, $msg) = @_;
4055 $errors->{$opt} = "hotplug problem - $msg";
4059 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4060 if ($fast_plug_option->{$opt}) {
4061 $conf->{$opt} = $conf->{pending}->{$opt};
4062 delete $conf->{pending}->{$opt};
4068 PVE::QemuConfig->write_config($vmid, $conf);
4069 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4072 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4074 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4075 while (my ($opt, $force) = each %$pending_delete_hash) {
4076 next if $selection && !$selection->{$opt};
4078 if ($opt eq 'hotplug
') {
4079 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4080 } elsif ($opt eq 'tablet
') {
4081 die "skip\n" if !$hotplug_features->{usb};
4082 if ($defaults->{tablet}) {
4083 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4085 vm_deviceunplug($vmid, $conf, $opt);
4087 } elsif ($opt =~ m/^usb\d+/) {
4089 # since we cannot reliably hot unplug usb devices
4090 # we are disabling it
4091 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4092 vm_deviceunplug($vmid, $conf, $opt);
4093 } elsif ($opt eq 'vcpus
') {
4094 die "skip\n" if !$hotplug_features->{cpu};
4095 qemu_cpu_hotplug($vmid, $conf, undef);
4096 } elsif ($opt eq 'balloon
') {
4097 # enable balloon device is not hotpluggable
4098 die "skip\n" if !defined($conf->{balloon}) || $conf->{balloon};
4099 } elsif ($fast_plug_option->{$opt}) {
4101 } elsif ($opt =~ m/^net(\d+)$/) {
4102 die "skip\n" if !$hotplug_features->{network};
4103 vm_deviceunplug($vmid, $conf, $opt);
4104 } elsif (is_valid_drivename($opt)) {
4105 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4106 vm_deviceunplug($vmid, $conf, $opt);
4107 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4108 } elsif ($opt =~ m/^memory$/) {
4109 die "skip\n" if !$hotplug_features->{memory};
4110 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4111 } elsif ($opt eq 'cpuunits
') {
4112 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4113 } elsif ($opt eq 'cpulimit
') {
4114 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4120 &$add_error($opt, $err) if $err ne "skip\n";
4122 # save new config if hotplug was successful
4123 delete $conf->{$opt};
4124 vmconfig_undelete_pending_option($conf, $opt);
4125 PVE::QemuConfig->write_config($vmid, $conf);
4126 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4130 foreach my $opt (keys %{$conf->{pending}}) {
4131 next if $selection && !$selection->{$opt};
4132 my $value = $conf->{pending}->{$opt};
4134 if ($opt eq 'hotplug
') {
4135 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4136 } elsif ($opt eq 'tablet
') {
4137 die "skip\n" if !$hotplug_features->{usb};
4139 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4140 } elsif ($value == 0) {
4141 vm_deviceunplug($vmid, $conf, $opt);
4143 } elsif ($opt =~ m/^usb\d+$/) {
4145 # since we cannot reliably hot unplug usb devices
4146 # we are disabling it
4147 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4148 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4149 die "skip\n" if !$d;
4150 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d);
4151 } elsif ($opt eq 'vcpus
') {
4152 die "skip\n" if !$hotplug_features->{cpu};
4153 qemu_cpu_hotplug($vmid, $conf, $value);
4154 } elsif ($opt eq 'balloon
') {
4155 # enable/disable balloning device is not hotpluggable
4156 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4157 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4158 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4160 # allow manual ballooning if shares is set to zero
4161 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4162 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4163 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4165 } elsif ($opt =~ m/^net(\d+)$/) {
4166 # some changes can be done without hotplug
4167 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4168 $vmid, $opt, $value);
4169 } elsif (is_valid_drivename($opt)) {
4170 # some changes can be done without hotplug
4171 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4172 $vmid, $opt, $value, 1);
4173 } elsif ($opt =~ m/^memory$/) { #dimms
4174 die "skip\n" if !$hotplug_features->{memory};
4175 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4176 } elsif ($opt eq 'cpuunits
') {
4177 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4178 } elsif ($opt eq 'cpulimit
') {
4179 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4180 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4182 die "skip\n"; # skip non-hot-pluggable options
4186 &$add_error($opt, $err) if $err ne "skip\n";
4188 # save new config if hotplug was successful
4189 $conf->{$opt} = $value;
4190 delete $conf->{pending}->{$opt};
4191 PVE::QemuConfig->write_config($vmid, $conf);
4192 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4197 sub try_deallocate_drive {
4198 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4200 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4201 my $volid = $drive->{file};
4202 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4203 my $sid = PVE::Storage::parse_volume_id($volid);
4204 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4206 # check if the disk is really unused
4207 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4208 if is_volume_in_use($storecfg, $conf, $key, $volid);
4209 PVE::Storage::vdisk_free($storecfg, $volid);
4212 # If vm is not owner of this disk remove from config
4220 sub vmconfig_delete_or_detach_drive {
4221 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4223 my $drive = parse_drive($opt, $conf->{$opt});
4225 my $rpcenv = PVE::RPCEnvironment::get();
4226 my $authuser = $rpcenv->get_user();
4229 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4230 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4232 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4236 sub vmconfig_apply_pending {
4237 my ($vmid, $conf, $storecfg) = @_;
4241 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4242 while (my ($opt, $force) = each %$pending_delete_hash) {
4243 die "internal error" if $opt =~ m/^unused/;
4244 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4245 if (!defined($conf->{$opt})) {
4246 vmconfig_undelete_pending_option($conf, $opt);
4247 PVE::QemuConfig->write_config($vmid, $conf);
4248 } elsif (is_valid_drivename($opt)) {
4249 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4250 vmconfig_undelete_pending_option($conf, $opt);
4251 delete $conf->{$opt};
4252 PVE::QemuConfig->write_config($vmid, $conf);
4254 vmconfig_undelete_pending_option($conf, $opt);
4255 delete $conf->{$opt};
4256 PVE::QemuConfig->write_config($vmid, $conf);
4260 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4262 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4263 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4265 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4266 # skip if nothing changed
4267 } elsif (is_valid_drivename($opt)) {
4268 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4269 if defined($conf->{$opt});
4270 $conf->{$opt} = $conf->{pending}->{$opt};
4272 $conf->{$opt} = $conf->{pending}->{$opt};
4275 delete $conf->{pending}->{$opt};
4276 PVE::QemuConfig->write_config($vmid, $conf);
4280 my $safe_num_ne = sub {
4283 return 0 if !defined($a) && !defined($b);
4284 return 1 if !defined($a);
4285 return 1 if !defined($b);
4290 my $safe_string_ne = sub {
4293 return 0 if !defined($a) && !defined($b);
4294 return 1 if !defined($a);
4295 return 1 if !defined($b);
4300 sub vmconfig_update_net {
4301 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value) = @_;
4303 my $newnet = parse_net($value);
4305 if ($conf->{$opt}) {
4306 my $oldnet = parse_net($conf->{$opt});
4308 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4309 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4310 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4311 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4313 # for non online change, we try to hot-unplug
4314 die "skip\n" if !$hotplug;
4315 vm_deviceunplug($vmid, $conf, $opt);
4318 die "internal error" if $opt !~ m/net(\d+)/;
4319 my $iface = "tap${vmid}i$1";
4321 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4322 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4323 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4324 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4325 PVE::Network::tap_unplug($iface);
4326 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4327 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4328 # Rate can be applied on its own but any change above needs to
4329 # include the rate in tap_plug since OVS resets everything.
4330 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4333 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4334 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4342 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet);
4348 sub vmconfig_update_disk {
4349 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force) = @_;
4351 # fixme: do we need force?
4353 my $drive = parse_drive($opt, $value);
4355 if ($conf->{$opt}) {
4357 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4359 my $media = $drive->{media} || 'disk
';
4360 my $oldmedia = $old_drive->{media} || 'disk
';
4361 die "unable to change media type\n" if $media ne $oldmedia;
4363 if (!drive_is_cdrom($old_drive)) {
4365 if ($drive->{file} ne $old_drive->{file}) {
4367 die "skip\n" if !$hotplug;
4369 # unplug and register as unused
4370 vm_deviceunplug($vmid, $conf, $opt);
4371 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4374 # update existing disk
4376 # skip non hotpluggable value
4377 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4378 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4379 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4380 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
4385 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4386 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4387 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4388 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4389 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4390 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4391 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4392 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4393 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4394 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4395 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4396 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4397 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4398 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4399 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4400 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4401 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4402 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4404 qemu_block_set_io_throttle($vmid,"drive-$opt",
4405 ($drive->{mbps} || 0)*1024*1024,
4406 ($drive->{mbps_rd} || 0)*1024*1024,
4407 ($drive->{mbps_wr} || 0)*1024*1024,
4408 $drive->{iops} || 0,
4409 $drive->{iops_rd} || 0,
4410 $drive->{iops_wr} || 0,
4411 ($drive->{mbps_max} || 0)*1024*1024,
4412 ($drive->{mbps_rd_max} || 0)*1024*1024,
4413 ($drive->{mbps_wr_max} || 0)*1024*1024,
4414 $drive->{iops_max} || 0,
4415 $drive->{iops_rd_max} || 0,
4416 $drive->{iops_wr_max} || 0,
4417 $drive->{bps_max_length} || 1,
4418 $drive->{bps_rd_max_length} || 1,
4419 $drive->{bps_wr_max_length} || 1,
4420 $drive->{iops_max_length} || 1,
4421 $drive->{iops_rd_max_length} || 1,
4422 $drive->{iops_wr_max_length} || 1);
4431 if ($drive->{file} eq 'none
') {
4432 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
4434 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4435 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
4436 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
4444 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4446 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
4447 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive);
4451 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
4452 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
4454 PVE::QemuConfig->lock_config($vmid, sub {
4455 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
4457 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
4459 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4461 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
4463 if (!$statefile && scalar(keys %{$conf->{pending}})) {
4464 vmconfig_apply_pending($vmid, $conf, $storecfg);
4465 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4468 my $defaults = load_defaults();
4470 # set environment variable useful inside network script
4471 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
4473 my $local_volumes = {};
4475 if( $targetstorage ){
4477 foreach_drive($conf, sub {
4478 my ($ds, $drive) = @_;
4480 return if drive_is_cdrom($drive);
4482 my $volid = $drive->{file};
4486 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
4488 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4489 return if $scfg->{shared};
4490 $local_volumes->{$ds} = [$volid, $storeid, $volname];
4495 foreach my $opt (sort keys %$local_volumes) {
4497 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
4498 my $drive = parse_drive($opt, $conf->{$opt});
4500 #if remote storage is specified, use default format
4501 if ($targetstorage && $targetstorage ne "1") {
4502 $storeid = $targetstorage;
4503 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
4504 $format = $defFormat;
4506 #else we use same format than original
4507 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4508 $format = qemu_img_format($scfg, $volid);
4511 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
4512 my $newdrive = $drive;
4513 $newdrive->{format} = $format;
4514 $newdrive->{file} = $newvolid;
4515 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
4516 $local_volumes->{$opt} = $drivestr;
4517 #pass drive to conf for command line
4518 $conf->{$opt} = $drivestr;
4522 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
4524 my $migrate_port = 0;
4527 if ($statefile eq 'tcp
') {
4528 my $localip = "localhost";
4529 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
4530 my $nodename = PVE::INotify::nodename();
4532 if (!defined($migration_type)) {
4533 if (defined($datacenterconf->{migration}->{type})) {
4534 $migration_type = $datacenterconf->{migration}->{type};
4536 $migration_type = 'secure
';
4540 if ($migration_type eq 'insecure
') {
4541 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
4542 if ($migrate_network_addr) {
4543 $localip = $migrate_network_addr;
4545 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
4548 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4551 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4552 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4553 $migrate_uri = "tcp:${localip}:${migrate_port}";
4554 push @$cmd, '-incoming
', $migrate_uri;
4557 } elsif ($statefile eq 'unix
') {
4558 # should be default for secure migrations as a ssh TCP forward
4559 # tunnel is not deterministic reliable ready and fails regurarly
4560 # to set up in time, so use UNIX socket forwards
4561 my $socket_addr = "/run/qemu-server/$vmid.migrate";
4562 unlink $socket_addr;
4564 $migrate_uri = "unix:$socket_addr";
4566 push @$cmd, '-incoming
', $migrate_uri;
4570 push @$cmd, '-loadstate
', $statefile;
4577 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
4578 my $d = parse_hostpci($conf->{"hostpci$i"});
4580 my $pcidevices = $d->{pciid};
4581 foreach my $pcidevice (@$pcidevices) {
4582 my $pciid = $pcidevice->{id}.".".$pcidevice->{function};
4584 my $info = pci_device_info("0000:$pciid");
4585 die "IOMMU not present\n" if !check_iommu_support();
4586 die "no pci device info for device '$pciid'\n" if !$info;
4587 die "can't unbind
/bind pci group to vfio
'$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
4588 die "can
't reset pci device '$pciid'\n" if $info->{has_fl_reset} and !pci_dev_reset($info);
4592 PVE::Storage::activate_volumes($storecfg, $vollist);
4594 if (!check_running($vmid, 1) && -d "/sys/fs/cgroup/systemd/qemu.slice/$vmid.scope") {
4596 push @$cmd, '/bin/systemctl
', 'stop
', "$vmid.scope";
4597 eval { run_command($cmd); };
4600 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
4601 : $defaults->{cpuunits};
4603 my %run_params = (timeout => $statefile ? undef : 30, umask => 0077);
4606 Slice => 'qemu
.slice
',
4608 CPUShares => $cpuunits
4611 if (my $cpulimit = $conf->{cpulimit}) {
4612 $properties{CPUQuota} = int($cpulimit * 100);
4614 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
4616 if ($conf->{hugepages}) {
4619 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
4620 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
4622 PVE::QemuServer::Memory::hugepages_mount();
4623 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
4626 PVE::Tools::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4627 run_command($cmd, %run_params);
4631 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
4635 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
4637 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
4641 PVE::Tools::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4642 run_command($cmd, %run_params);
4647 # deactivate volumes if start fails
4648 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
4649 die "start failed: $err";
4652 print "migration listens on $migrate_uri\n" if $migrate_uri;
4654 if ($statefile && $statefile ne 'tcp
') {
4655 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
4659 #start nbd server for storage migration
4660 if ($targetstorage) {
4662 my $nodename = PVE::INotify::nodename();
4663 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
4664 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
4665 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4666 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4668 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${migrate_port}" } } );
4670 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4672 foreach my $opt (sort keys %$local_volumes) {
4673 my $volid = $local_volumes->{$opt};
4674 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
4675 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
4676 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
4680 if ($migratedfrom) {
4683 set_migration_caps($vmid);
4688 print "spice listens on port $spice_port\n";
4689 if ($spice_ticket) {
4690 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
4691 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
4697 if (!$statefile && (!defined($conf->{balloon}) || $conf->{balloon})) {
4698 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
4699 if $conf->{balloon};
4702 foreach my $opt (keys %$conf) {
4703 next if $opt !~ m/^net\d+$/;
4704 my $nicconf = parse_net($conf->{$opt});
4705 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
4709 vm_mon_cmd_nocheck($vmid, 'qom-set
',
4710 path => "machine/peripheral/balloon0",
4711 property => "guest-stats-polling-interval",
4712 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
4718 my ($vmid, $execute, %params) = @_;
4720 my $cmd = { execute => $execute, arguments => \%params };
4721 vm_qmp_command($vmid, $cmd);
4724 sub vm_mon_cmd_nocheck {
4725 my ($vmid, $execute, %params) = @_;
4727 my $cmd = { execute => $execute, arguments => \%params };
4728 vm_qmp_command($vmid, $cmd, 1);
4731 sub vm_qmp_command {
4732 my ($vmid, $cmd, $nocheck) = @_;
4737 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
4738 $timeout = $cmd->{arguments}->{timeout};
4739 delete $cmd->{arguments}->{timeout};
4743 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
4744 my $sname = qmp_socket($vmid);
4745 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
4746 my $qmpclient = PVE::QMPClient->new();
4748 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
4749 } elsif (-e "${var_run_tmpdir}/$vmid.mon") {
4750 die "can't execute complex command on old monitor
- stop
/start your vm to fix the problem
\n"
4751 if scalar(%{$cmd->{arguments}});
4752 vm_monitor_command($vmid, $cmd->{execute}, $nocheck);
4754 die "unable to
open monitor
socket\n";
4758 syslog("err
", "VM
$vmid qmp command failed
- $err");
4765 sub vm_human_monitor_command {
4766 my ($vmid, $cmdline) = @_;
4771 execute => 'human-monitor-command',
4772 arguments => { 'command-line' => $cmdline},
4775 return vm_qmp_command($vmid, $cmd);
4778 sub vm_commandline {
4779 my ($storecfg, $vmid) = @_;
4781 my $conf = PVE::QemuConfig->load_config($vmid);
4783 my $defaults = load_defaults();
4785 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
4787 return PVE::Tools::cmd2string($cmd);
4791 my ($vmid, $skiplock) = @_;
4793 PVE::QemuConfig->lock_config($vmid, sub {
4795 my $conf = PVE::QemuConfig->load_config($vmid);
4797 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4799 vm_mon_cmd($vmid, "system_reset
");
4803 sub get_vm_volumes {
4807 foreach_volid($conf, sub {
4808 my ($volid, $is_cdrom) = @_;
4810 return if $volid =~ m|^/|;
4812 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
4815 push @$vollist, $volid;
4821 sub vm_stop_cleanup {
4822 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
4827 my $vollist = get_vm_volumes($conf);
4828 PVE::Storage::deactivate_volumes($storecfg, $vollist);
4831 foreach my $ext (qw(mon qmp pid vnc qga)) {
4832 unlink "/var/run/qemu-server/${vmid}.$ext";
4835 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
4837 warn $@ if $@; # avoid errors - just warn
4840 # Note: use $nockeck to skip tests if VM configuration file exists.
4841 # We need that when migration VMs to other nodes (files already moved)
4842 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
4844 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
4846 $force = 1 if !defined($force) && !$shutdown;
4849 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
4850 kill 15, $pid if $pid;
4851 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
4852 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
4856 PVE
::QemuConfig-
>lock_config($vmid, sub {
4858 my $pid = check_running
($vmid, $nocheck);
4863 $conf = PVE
::QemuConfig-
>load_config($vmid);
4864 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
4865 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
4866 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
4867 $timeout = $opts->{down
} if $opts->{down
};
4871 $timeout = 60 if !defined($timeout);
4875 if (defined($conf) && $conf->{agent
}) {
4876 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
4878 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
4881 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
4888 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
4893 if ($count >= $timeout) {
4895 warn "VM still running - terminating now with SIGTERM\n";
4898 die "VM quit/powerdown failed - got timeout\n";
4901 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
4906 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
4909 die "VM quit/powerdown failed\n";
4917 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
4922 if ($count >= $timeout) {
4923 warn "VM still running - terminating now with SIGKILL\n";
4928 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
4933 my ($vmid, $skiplock) = @_;
4935 PVE
::QemuConfig-
>lock_config($vmid, sub {
4937 my $conf = PVE
::QemuConfig-
>load_config($vmid);
4939 PVE
::QemuConfig-
>check_lock($conf)
4940 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
4942 vm_mon_cmd
($vmid, "stop");
4947 my ($vmid, $skiplock, $nocheck) = @_;
4949 PVE
::QemuConfig-
>lock_config($vmid, sub {
4953 my $conf = PVE
::QemuConfig-
>load_config($vmid);
4955 PVE
::QemuConfig-
>check_lock($conf)
4956 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
4958 vm_mon_cmd
($vmid, "cont");
4961 vm_mon_cmd_nocheck
($vmid, "cont");
4967 my ($vmid, $skiplock, $key) = @_;
4969 PVE
::QemuConfig-
>lock_config($vmid, sub {
4971 my $conf = PVE
::QemuConfig-
>load_config($vmid);
4973 # there is no qmp command, so we use the human monitor command
4974 vm_human_monitor_command
($vmid, "sendkey $key");
4979 my ($storecfg, $vmid, $skiplock) = @_;
4981 PVE
::QemuConfig-
>lock_config($vmid, sub {
4983 my $conf = PVE
::QemuConfig-
>load_config($vmid);
4985 if (!check_running
($vmid)) {
4986 destroy_vm
($storecfg, $vmid, undef, $skiplock);
4988 die "VM $vmid is running - destroy failed\n";
4996 my ($filename, $buf) = @_;
4998 my $fh = IO
::File-
>new($filename, "w");
4999 return undef if !$fh;
5001 my $res = print $fh $buf;
5008 sub pci_device_info
{
5013 return undef if $name !~ m/^([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\.([a-f0-9])$/;
5014 my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4);
5016 my $irq = file_read_firstline
("$pcisysfs/devices/$name/irq");
5017 return undef if !defined($irq) || $irq !~ m/^\d+$/;
5019 my $vendor = file_read_firstline
("$pcisysfs/devices/$name/vendor");
5020 return undef if !defined($vendor) || $vendor !~ s/^0x//;
5022 my $product = file_read_firstline
("$pcisysfs/devices/$name/device");
5023 return undef if !defined($product) || $product !~ s/^0x//;
5028 product
=> $product,
5034 has_fl_reset
=> -f
"$pcisysfs/devices/$name/reset" || 0,
5043 my $name = $dev->{name
};
5045 my $fn = "$pcisysfs/devices/$name/reset";
5047 return file_write
($fn, "1");
5050 sub pci_dev_bind_to_vfio
{
5053 my $name = $dev->{name
};
5055 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5057 if (!-d
$vfio_basedir) {
5058 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5060 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5062 my $testdir = "$vfio_basedir/$name";
5063 return 1 if -d
$testdir;
5065 my $data = "$dev->{vendor} $dev->{product}";
5066 return undef if !file_write
("$vfio_basedir/new_id", $data);
5068 my $fn = "$pcisysfs/devices/$name/driver/unbind";
5069 if (!file_write
($fn, $name)) {
5070 return undef if -f
$fn;
5073 $fn = "$vfio_basedir/bind";
5074 if (! -d
$testdir) {
5075 return undef if !file_write
($fn, $name);
5081 sub pci_dev_group_bind_to_vfio
{
5084 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5086 if (!-d
$vfio_basedir) {
5087 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5089 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5091 # get IOMMU group devices
5092 opendir(my $D, "$pcisysfs/devices/0000:$pciid/iommu_group/devices/") || die "Cannot open iommu_group: $!\n";
5093 my @devs = grep /^0000:/, readdir($D);
5096 foreach my $pciid (@devs) {
5097 $pciid =~ m/^([:\.\da-f]+)$/ or die "PCI ID $pciid not valid!\n";
5099 # pci bridges, switches or root ports are not supported
5100 # they have a pci_bus subdirectory so skip them
5101 next if (-e
"$pcisysfs/devices/$pciid/pci_bus");
5103 my $info = pci_device_info
($1);
5104 pci_dev_bind_to_vfio
($info) || die "Cannot bind $pciid to vfio\n";
5110 # vzdump restore implementaion
5112 sub tar_archive_read_firstfile
{
5113 my $archive = shift;
5115 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5117 # try to detect archive type first
5118 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5119 die "unable to open file '$archive'\n";
5120 my $firstfile = <$fh>;
5124 die "ERROR: archive contaions no data\n" if !$firstfile;
5130 sub tar_restore_cleanup
{
5131 my ($storecfg, $statfile) = @_;
5133 print STDERR
"starting cleanup\n";
5135 if (my $fd = IO
::File-
>new($statfile, "r")) {
5136 while (defined(my $line = <$fd>)) {
5137 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5140 if ($volid =~ m
|^/|) {
5141 unlink $volid || die 'unlink failed\n';
5143 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5145 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5147 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5149 print STDERR
"unable to parse line in statfile - $line";
5156 sub restore_archive
{
5157 my ($archive, $vmid, $user, $opts) = @_;
5159 my $format = $opts->{format
};
5162 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5163 $format = 'tar' if !$format;
5165 } elsif ($archive =~ m/\.tar$/) {
5166 $format = 'tar' if !$format;
5167 } elsif ($archive =~ m/.tar.lzo$/) {
5168 $format = 'tar' if !$format;
5170 } elsif ($archive =~ m/\.vma$/) {
5171 $format = 'vma' if !$format;
5172 } elsif ($archive =~ m/\.vma\.gz$/) {
5173 $format = 'vma' if !$format;
5175 } elsif ($archive =~ m/\.vma\.lzo$/) {
5176 $format = 'vma' if !$format;
5179 $format = 'vma' if !$format; # default
5182 # try to detect archive format
5183 if ($format eq 'tar') {
5184 return restore_tar_archive
($archive, $vmid, $user, $opts);
5186 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5190 sub restore_update_config_line
{
5191 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5193 return if $line =~ m/^\#qmdump\#/;
5194 return if $line =~ m/^\#vzdump\#/;
5195 return if $line =~ m/^lock:/;
5196 return if $line =~ m/^unused\d+:/;
5197 return if $line =~ m/^parent:/;
5198 return if $line =~ m/^template:/; # restored VM is never a template
5200 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5201 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5202 # try to convert old 1.X settings
5203 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5204 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5205 my ($model, $macaddr) = split(/\=/, $devconfig);
5206 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5209 bridge
=> "vmbr$ind",
5210 macaddr
=> $macaddr,
5212 my $netstr = print_net
($net);
5214 print $outfd "net$cookie->{netcount}: $netstr\n";
5215 $cookie->{netcount
}++;
5217 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5218 my ($id, $netstr) = ($1, $2);
5219 my $net = parse_net
($netstr);
5220 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5221 $netstr = print_net
($net);
5222 print $outfd "$id: $netstr\n";
5223 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5226 my $di = parse_drive
($virtdev, $value);
5227 if (defined($di->{backup
}) && !$di->{backup
}) {
5228 print $outfd "#$line";
5229 } elsif ($map->{$virtdev}) {
5230 delete $di->{format
}; # format can change on restore
5231 $di->{file
} = $map->{$virtdev};
5232 $value = print_drive
($vmid, $di);
5233 print $outfd "$virtdev: $value\n";
5243 my ($cfg, $vmid) = @_;
5245 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5247 my $volid_hash = {};
5248 foreach my $storeid (keys %$info) {
5249 foreach my $item (@{$info->{$storeid}}) {
5250 next if !($item->{volid
} && $item->{size
});
5251 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5252 $volid_hash->{$item->{volid
}} = $item;
5259 sub is_volume_in_use
{
5260 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5262 my $path = PVE
::Storage
::path
($storecfg, $volid);
5264 my $scan_config = sub {
5265 my ($cref, $snapname) = @_;
5267 foreach my $key (keys %$cref) {
5268 my $value = $cref->{$key};
5269 if (is_valid_drivename
($key)) {
5270 next if $skip_drive && $key eq $skip_drive;
5271 my $drive = parse_drive
($key, $value);
5272 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5273 return 1 if $volid eq $drive->{file
};
5274 if ($drive->{file
} =~ m!^/!) {
5275 return 1 if $drive->{file
} eq $path;
5277 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5279 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5281 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5289 return 1 if &$scan_config($conf);
5293 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5294 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5300 sub update_disksize
{
5301 my ($vmid, $conf, $volid_hash) = @_;
5307 # Note: it is allowed to define multiple storages with same path (alias), so
5308 # we need to check both 'volid' and real 'path' (two different volid can point
5309 # to the same path).
5314 foreach my $opt (keys %$conf) {
5315 if (is_valid_drivename
($opt)) {
5316 my $drive = parse_drive
($opt, $conf->{$opt});
5317 my $volid = $drive->{file
};
5320 $used->{$volid} = 1;
5321 if ($volid_hash->{$volid} &&
5322 (my $path = $volid_hash->{$volid}->{path
})) {
5323 $usedpath->{$path} = 1;
5326 next if drive_is_cdrom
($drive);
5327 next if !$volid_hash->{$volid};
5329 $drive->{size
} = $volid_hash->{$volid}->{size
};
5330 my $new = print_drive
($vmid, $drive);
5331 if ($new ne $conf->{$opt}) {
5333 $conf->{$opt} = $new;
5338 # remove 'unusedX' entry if volume is used
5339 foreach my $opt (keys %$conf) {
5340 next if $opt !~ m/^unused\d+$/;
5341 my $volid = $conf->{$opt};
5342 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5343 if ($used->{$volid} || ($path && $usedpath->{$path})) {
5345 delete $conf->{$opt};
5349 foreach my $volid (sort keys %$volid_hash) {
5350 next if $volid =~ m/vm-$vmid-state-/;
5351 next if $used->{$volid};
5352 my $path = $volid_hash->{$volid}->{path
};
5353 next if !$path; # just to be sure
5354 next if $usedpath->{$path};
5356 PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5357 $usedpath->{$path} = 1; # avoid to add more than once (aliases)
5364 my ($vmid, $nolock) = @_;
5366 my $cfg = PVE
::Storage
::config
();
5368 my $volid_hash = scan_volids
($cfg, $vmid);
5370 my $updatefn = sub {
5373 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5375 PVE
::QemuConfig-
>check_lock($conf);
5378 foreach my $volid (keys %$volid_hash) {
5379 my $info = $volid_hash->{$volid};
5380 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5383 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5385 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes;
5388 if (defined($vmid)) {
5392 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5395 my $vmlist = config_list
();
5396 foreach my $vmid (keys %$vmlist) {
5400 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5406 sub restore_vma_archive
{
5407 my ($archive, $vmid, $user, $opts, $comp) = @_;
5409 my $input = $archive eq '-' ?
"<&STDIN" : undef;
5410 my $readfrom = $archive;
5415 my $qarchive = PVE
::Tools
::shellquote
($archive);
5416 if ($comp eq 'gzip') {
5417 $uncomp = "zcat $qarchive|";
5418 } elsif ($comp eq 'lzop') {
5419 $uncomp = "lzop -d -c $qarchive|";
5421 die "unknown compression method '$comp'\n";
5426 my $tmpdir = "/var/tmp/vzdumptmp$$";
5429 # disable interrupts (always do cleanups)
5430 local $SIG{INT
} = $SIG{TERM
} = $SIG{QUIT
} = $SIG{HUP
} = sub {
5431 warn "got interrupt - ignored\n";
5434 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
5435 POSIX
::mkfifo
($mapfifo, 0600);
5438 my $openfifo = sub {
5439 open($fifofh, '>', $mapfifo) || die $!;
5442 my $cmd = "${uncomp}vma extract -v -r $mapfifo $readfrom $tmpdir";
5449 my $rpcenv = PVE
::RPCEnvironment
::get
();
5451 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5452 my $tmpfn = "$conffile.$$.tmp";
5454 # Note: $oldconf is undef if VM does not exists
5455 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
5456 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
5458 my $print_devmap = sub {
5459 my $virtdev_hash = {};
5461 my $cfgfn = "$tmpdir/qemu-server.conf";
5463 # we can read the config - that is already extracted
5464 my $fh = IO
::File-
>new($cfgfn, "r") ||
5465 "unable to read qemu-server.conf - $!\n";
5467 my $fwcfgfn = "$tmpdir/qemu-server.fw";
5469 my $pve_firewall_dir = '/etc/pve/firewall';
5470 mkdir $pve_firewall_dir; # make sure the dir exists
5471 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
5474 while (defined(my $line = <$fh>)) {
5475 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
5476 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
5477 die "archive does not contain data for drive '$virtdev'\n"
5478 if !$devinfo->{$devname};
5479 if (defined($opts->{storage
})) {
5480 $storeid = $opts->{storage
} || 'local';
5481 } elsif (!$storeid) {
5484 $format = 'raw' if !$format;
5485 $devinfo->{$devname}->{devname
} = $devname;
5486 $devinfo->{$devname}->{virtdev
} = $virtdev;
5487 $devinfo->{$devname}->{format
} = $format;
5488 $devinfo->{$devname}->{storeid
} = $storeid;
5490 # check permission on storage
5491 my $pool = $opts->{pool
}; # todo: do we need that?
5492 if ($user ne 'root@pam') {
5493 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
5496 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
5500 foreach my $devname (keys %$devinfo) {
5501 die "found no device mapping information for device '$devname'\n"
5502 if !$devinfo->{$devname}->{virtdev
};
5505 my $cfg = PVE
::Storage
::config
();
5507 # create empty/temp config
5509 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
5510 foreach_drive
($oldconf, sub {
5511 my ($ds, $drive) = @_;
5513 return if drive_is_cdrom
($drive);
5515 my $volid = $drive->{file
};
5517 return if !$volid || $volid =~ m
|^/|;
5519 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
5520 return if !$path || !$owner || ($owner != $vmid);
5522 # Note: only delete disk we want to restore
5523 # other volumes will become unused
5524 if ($virtdev_hash->{$ds}) {
5525 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
5532 # delete vmstate files
5533 # since after the restore we have no snapshots anymore
5534 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
5535 my $snap = $oldconf->{snapshots
}->{$snapname};
5536 if ($snap->{vmstate
}) {
5537 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
5546 foreach my $virtdev (sort keys %$virtdev_hash) {
5547 my $d = $virtdev_hash->{$virtdev};
5548 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
5549 my $scfg = PVE
::Storage
::storage_config
($cfg, $d->{storeid
});
5551 # test if requested format is supported
5552 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $d->{storeid
});
5553 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
5554 $d->{format
} = $defFormat if !$supported;
5556 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $d->{storeid
}, $vmid,
5557 $d->{format
}, undef, $alloc_size);
5558 print STDERR
"new volume ID is '$volid'\n";
5559 $d->{volid
} = $volid;
5560 my $path = PVE
::Storage
::path
($cfg, $volid);
5562 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
5564 my $write_zeros = 1;
5565 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
5569 print $fifofh "format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
5571 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
5572 $map->{$virtdev} = $volid;
5575 $fh->seek(0, 0) || die "seek failed - $!\n";
5577 my $outfd = new IO
::File
($tmpfn, "w") ||
5578 die "unable to write config for VM $vmid\n";
5580 my $cookie = { netcount
=> 0 };
5581 while (defined(my $line = <$fh>)) {
5582 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
5591 local $SIG{INT
} = $SIG{TERM
} = $SIG{QUIT
} = $SIG{HUP
} = $SIG{PIPE
} = sub {
5592 die "interrupted by signal\n";
5594 local $SIG{ALRM
} = sub { die "got timeout\n"; };
5596 $oldtimeout = alarm($timeout);
5603 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
5604 my ($dev_id, $size, $devname) = ($1, $2, $3);
5605 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
5606 } elsif ($line =~ m/^CTIME: /) {
5607 # we correctly received the vma config, so we can disable
5608 # the timeout now for disk allocation (set to 10 minutes, so
5609 # that we always timeout if something goes wrong)
5612 print $fifofh "done\n";
5613 my $tmp = $oldtimeout || 0;
5614 $oldtimeout = undef;
5620 print "restore vma archive: $cmd\n";
5621 run_command
($cmd, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
5625 alarm($oldtimeout) if $oldtimeout;
5628 foreach my $devname (keys %$devinfo) {
5629 my $volid = $devinfo->{$devname}->{volid
};
5630 push @$vollist, $volid if $volid;
5633 my $cfg = PVE
::Storage
::config
();
5634 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
5642 foreach my $devname (keys %$devinfo) {
5643 my $volid = $devinfo->{$devname}->{volid
};
5646 if ($volid =~ m
|^/|) {
5647 unlink $volid || die 'unlink failed\n';
5649 PVE
::Storage
::vdisk_free
($cfg, $volid);
5651 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5653 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5660 rename($tmpfn, $conffile) ||
5661 die "unable to commit configuration file '$conffile'\n";
5663 PVE
::Cluster
::cfs_update
(); # make sure we read new file
5665 eval { rescan
($vmid, 1); };
5669 sub restore_tar_archive
{
5670 my ($archive, $vmid, $user, $opts) = @_;
5672 if ($archive ne '-') {
5673 my $firstfile = tar_archive_read_firstfile
($archive);
5674 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
5675 if $firstfile ne 'qemu-server.conf';
5678 my $storecfg = PVE
::Storage
::config
();
5680 # destroy existing data - keep empty config
5681 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
5682 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
5684 my $tocmd = "/usr/lib/qemu-server/qmextract";
5686 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
5687 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
5688 $tocmd .= ' --prealloc' if $opts->{prealloc
};
5689 $tocmd .= ' --info' if $opts->{info
};
5691 # tar option "xf" does not autodetect compression when read from STDIN,
5692 # so we pipe to zcat
5693 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
5694 PVE
::Tools
::shellquote
("--to-command=$tocmd");
5696 my $tmpdir = "/var/tmp/vzdumptmp$$";
5699 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
5700 local $ENV{VZDUMP_VMID
} = $vmid;
5701 local $ENV{VZDUMP_USER
} = $user;
5703 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5704 my $tmpfn = "$conffile.$$.tmp";
5706 # disable interrupts (always do cleanups)
5707 local $SIG{INT
} = $SIG{TERM
} = $SIG{QUIT
} = $SIG{HUP
} = sub {
5708 print STDERR
"got interrupt - ignored\n";
5713 local $SIG{INT
} = $SIG{TERM
} = $SIG{QUIT
} = $SIG{HUP
} = $SIG{PIPE
} = sub {
5714 die "interrupted by signal\n";
5717 if ($archive eq '-') {
5718 print "extracting archive from STDIN\n";
5719 run_command
($cmd, input
=> "<&STDIN");
5721 print "extracting archive '$archive'\n";
5725 return if $opts->{info
};
5729 my $statfile = "$tmpdir/qmrestore.stat";
5730 if (my $fd = IO
::File-
>new($statfile, "r")) {
5731 while (defined (my $line = <$fd>)) {
5732 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5733 $map->{$1} = $2 if $1;
5735 print STDERR
"unable to parse line in statfile - $line\n";
5741 my $confsrc = "$tmpdir/qemu-server.conf";
5743 my $srcfd = new IO
::File
($confsrc, "r") ||
5744 die "unable to open file '$confsrc'\n";
5746 my $outfd = new IO
::File
($tmpfn, "w") ||
5747 die "unable to write config for VM $vmid\n";
5749 my $cookie = { netcount
=> 0 };
5750 while (defined (my $line = <$srcfd>)) {
5751 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
5763 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
5770 rename $tmpfn, $conffile ||
5771 die "unable to commit configuration file '$conffile'\n";
5773 PVE
::Cluster
::cfs_update
(); # make sure we read new file
5775 eval { rescan
($vmid, 1); };
5779 sub foreach_writable_storage
{
5780 my ($conf, $func) = @_;
5784 foreach my $ds (keys %$conf) {
5785 next if !is_valid_drivename
($ds);
5787 my $drive = parse_drive
($ds, $conf->{$ds});
5789 next if drive_is_cdrom
($drive);
5791 my $volid = $drive->{file
};
5793 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
5794 $sidhash->{$sid} = $sid if $sid;
5797 foreach my $sid (sort keys %$sidhash) {
5802 sub do_snapshots_with_qemu
{
5803 my ($storecfg, $volid) = @_;
5805 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
5807 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
5808 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
5812 if ($volid =~ m/\.(qcow2|qed)$/){
5819 sub qga_check_running
{
5822 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
5824 warn "Qemu Guest Agent are not running - $@";
5830 sub template_create
{
5831 my ($vmid, $conf, $disk) = @_;
5833 my $storecfg = PVE
::Storage
::config
();
5835 foreach_drive
($conf, sub {
5836 my ($ds, $drive) = @_;
5838 return if drive_is_cdrom
($drive);
5839 return if $disk && $ds ne $disk;
5841 my $volid = $drive->{file
};
5842 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
5844 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
5845 $drive->{file
} = $voliddst;
5846 $conf->{$ds} = print_drive
($vmid, $drive);
5847 PVE
::QemuConfig-
>write_config($vmid, $conf);
5851 sub qemu_img_convert
{
5852 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
5854 my $storecfg = PVE
::Storage
::config
();
5855 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
5856 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
5858 if ($src_storeid && $dst_storeid) {
5860 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
5862 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
5863 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
5865 my $src_format = qemu_img_format
($src_scfg, $src_volname);
5866 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
5868 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
5869 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
5872 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
5873 push @$cmd, '-s', $snapname if($snapname && $src_format eq "qcow2");
5874 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
5875 if ($is_zero_initialized) {
5876 push @$cmd, "zeroinit:$dst_path";
5878 push @$cmd, $dst_path;
5883 if($line =~ m/\((\S+)\/100\
%\)/){
5885 my $transferred = int($size * $percent / 100);
5886 my $remaining = $size - $transferred;
5888 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
5893 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
5895 die "copy failed: $err" if $err;
5899 sub qemu_img_format
{
5900 my ($scfg, $volname) = @_;
5902 if ($scfg->{path
} && $volname =~ m/\.(raw|cow|qcow|qcow2|qed|vmdk|cloop)$/) {
5909 sub qemu_drive_mirror
{
5910 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete) = @_;
5912 $jobs = {} if !$jobs;
5916 $jobs->{"drive-$drive"} = {};
5918 if($dst_volid =~ /^nbd:(localhost|[\d\.]+|\[[\d\.:a-fA-F]+\]):(\d+):exportname=(\S+)/) {
5921 my $exportname = $3;
5924 my $unixsocket = "/run/qemu-server/$vmid.mirror-drive-$drive";
5925 $qemu_target = "nbd+unix:///$exportname?socket=$unixsocket";
5926 my $cmd = ['socat', "UNIX-LISTEN:$unixsocket,fork", "TCP:$server:$2,connect-timeout=1"];
5929 if (!defined($pid)) {
5930 die "forking socat tunnel failed";
5931 } elsif ($pid == 0) {
5936 $jobs->{"drive-$drive"}->{pid
} = $pid;
5940 last if -S
$unixsocket;
5941 die if $timeout > 5;
5948 my $storecfg = PVE
::Storage
::config
();
5949 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
5951 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
5953 $format = qemu_img_format
($dst_scfg, $dst_volname);
5955 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
5957 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
5960 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
5961 $opts->{format
} = $format if $format;
5963 print "drive mirror is starting for drive-$drive\n";
5965 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
5968 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
5969 die "mirroring error: $err";
5973 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete);
5976 sub qemu_drive_mirror_monitor
{
5977 my ($vmid, $vmiddst, $jobs, $skipcomplete) = @_;
5981 my $err_complete = 0;
5984 die "storage migration timed out\n" if $err_complete > 300;
5986 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
5988 my $running_mirror_jobs = {};
5989 foreach my $stat (@$stats) {
5990 next if $stat->{type
} ne 'mirror';
5991 $running_mirror_jobs->{$stat->{device
}} = $stat;
5994 my $readycounter = 0;
5996 foreach my $job (keys %$jobs) {
5998 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
5999 print "$job : finished\n";
6000 delete $jobs->{$job};
6004 die "$job: mirroring has been cancelled. Maybe do you have bad sectors?" if !defined($running_mirror_jobs->{$job});
6006 my $busy = $running_mirror_jobs->{$job}->{busy
};
6007 my $ready = $running_mirror_jobs->{$job}->{ready
};
6008 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6009 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6010 my $remaining = $total - $transferred;
6011 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6013 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6016 $readycounter++ if $running_mirror_jobs->{$job}->{ready
} eq 'true';
6019 last if scalar(keys %$jobs) == 0;
6021 if ($readycounter == scalar(keys %$jobs)) {
6022 print "all mirroring jobs are ready \n";
6023 last if $skipcomplete; #do the complete later
6025 if ($vmiddst && $vmiddst != $vmid) {
6026 # if we clone a disk for a new target vm, we don't switch the disk
6027 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6031 foreach my $job (keys %$jobs) {
6032 # try to switch the disk if source and destination are on the same guest
6033 print "$job : Try to complete block job\n";
6035 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6036 if ($@ =~ m/cannot be completed/) {
6037 print "$job : block job cannot be complete. Try again \n";
6040 print "$job : complete ok : flushing pending writes\n";
6041 $jobs->{$job}->{complete
} = 1;
6042 eval { qemu_blockjobs_finish_tunnel
($vmid, $job, $jobs->{$job}->{pid
}) } ;
6053 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6054 die "mirroring error: $err";
6059 sub qemu_blockjobs_cancel
{
6060 my ($vmid, $jobs) = @_;
6062 foreach my $job (keys %$jobs) {
6063 print "$job: try to cancel block job\n";
6064 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6065 $jobs->{$job}->{cancel
} = 1;
6069 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6071 my $running_jobs = {};
6072 foreach my $stat (@$stats) {
6073 $running_jobs->{$stat->{device
}} = $stat;
6076 foreach my $job (keys %$jobs) {
6078 if(defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6079 print "$job : finished\n";
6080 eval { qemu_blockjobs_finish_tunnel
($vmid, $job, $jobs->{$job}->{pid
}) } ;
6081 delete $jobs->{$job};
6085 last if scalar(keys %$jobs) == 0;
6091 sub qemu_blockjobs_finish_tunnel
{
6092 my ($vmid, $job, $cpid) = @_;
6096 for (my $i = 1; $i < 20; $i++) {
6097 my $waitpid = waitpid($cpid, WNOHANG
);
6098 last if (defined($waitpid) && ($waitpid == $cpid));
6102 } elsif ($i >= 15) {
6107 unlink "/run/qemu-server/$vmid.mirror-$job";
6111 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6112 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete) = @_;
6117 print "create linked clone of drive $drivename ($drive->{file})\n";
6118 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6119 push @$newvollist, $newvolid;
6122 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6123 $storeid = $storage if $storage;
6125 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6127 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6128 $format = qemu_img_format
($scfg, $volname);
6131 # test if requested format is supported - else use default
6132 my $supported = grep { $_ eq $format } @$validFormats;
6133 $format = $defFormat if !$supported;
6135 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6137 print "create full clone of drive $drivename ($drive->{file})\n";
6138 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $format, undef, ($size/1024));
6139 push @$newvollist, $newvolid;
6141 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6143 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6144 if (!$running || $snapname) {
6145 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6148 my $kvmver = get_running_qemu_version
($vmid);
6149 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
6150 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6151 if $drive->{iothread
};
6154 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete);
6158 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6161 $disk->{format
} = undef;
6162 $disk->{file
} = $newvolid;
6163 $disk->{size
} = $size;
6168 # this only works if VM is running
6169 sub get_current_qemu_machine
{
6172 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
6173 my $res = vm_qmp_command
($vmid, $cmd);
6175 my ($current, $default);
6176 foreach my $e (@$res) {
6177 $default = $e->{name
} if $e->{'is-default'};
6178 $current = $e->{name
} if $e->{'is-current'};
6181 # fallback to the default machine if current is not supported by qemu
6182 return $current || $default || 'pc';
6185 sub get_running_qemu_version
{
6187 my $cmd = { execute
=> 'query-version', arguments
=> {} };
6188 my $res = vm_qmp_command
($vmid, $cmd);
6189 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6192 sub qemu_machine_feature_enabled
{
6193 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6198 if ($machine && $machine =~ m/^(pc(-i440fx|-q35)?-(\d+)\.(\d+))/) {
6200 $current_major = $3;
6201 $current_minor = $4;
6203 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6205 $current_major = $1;
6206 $current_minor = $2;
6209 return 1 if $current_major >= $version_major && $current_minor >= $version_minor;
6214 sub qemu_machine_pxe
{
6215 my ($vmid, $conf, $machine) = @_;
6217 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6219 foreach my $opt (keys %$conf) {
6220 next if $opt !~ m/^net(\d+)$/;
6221 my $net = PVE
::QemuServer
::parse_net
($conf->{$opt});
6223 my $romfile = PVE
::QemuServer
::vm_mon_cmd_nocheck
($vmid, 'qom-get', path
=> $opt, property
=> 'romfile');
6224 return $machine.".pxe" if $romfile =~ m/pxe/;
6231 sub qemu_use_old_bios_files
{
6232 my ($machine_type) = @_;
6234 return if !$machine_type;
6236 my $use_old_bios_files = undef;
6238 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6240 $use_old_bios_files = 1;
6242 my $kvmver = kvm_user_version
();
6243 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6244 # load new efi bios files on migration. So this hack is required to allow
6245 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6246 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6247 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6250 return ($use_old_bios_files, $machine_type);
6257 dir_glob_foreach
("$pcisysfs/devices", '[a-f0-9]{4}:([a-f0-9]{2}:[a-f0-9]{2})\.([0-9])', sub {
6258 my (undef, $id, $function) = @_;
6259 my $res = { id
=> $id, function
=> $function};
6260 push @{$devices->{$id}}, $res;
6266 sub vm_iothreads_list
{
6269 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6272 foreach my $iothread (@$res) {
6273 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6280 my ($conf, $drive) = @_;
6284 if ($conf->{scsihw
} && ($conf->{scsihw
} =~ m/^lsi/)) {
6286 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6292 my $controller = int($drive->{index} / $maxdev);
6293 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6295 return ($maxdev, $controller, $controller_prefix);
6298 sub add_hyperv_enlighments
{
6299 my ($cpuFlags, $winversion, $machine_type, $kvmver, $nokvm, $bios, $gpu_passthrough) = @_;
6302 return if $winversion < 6;
6303 return if $bios && $bios eq 'ovmf' && $winversion < 8;
6305 push @$cpuFlags , 'hv_vendor_id=proxmox' if $gpu_passthrough;
6307 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
6308 push @$cpuFlags , 'hv_spinlocks=0x1fff';
6309 push @$cpuFlags , 'hv_vapic';
6310 push @$cpuFlags , 'hv_time';
6312 push @$cpuFlags , 'hv_spinlocks=0xffff';
6315 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
6316 push @$cpuFlags , 'hv_reset';
6317 push @$cpuFlags , 'hv_vpindex';
6318 push @$cpuFlags , 'hv_runtime';
6321 if ($winversion >= 7) {
6322 push @$cpuFlags , 'hv_relaxed';
6326 sub windows_version
{
6329 return 0 if !$ostype;
6333 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6335 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6337 } elsif ($ostype =~ m/^win(\d+)$/) {
6344 # bash completion helper
6346 sub complete_backup_archives
{
6347 my ($cmdname, $pname, $cvalue) = @_;
6349 my $cfg = PVE
::Storage
::config
();
6353 if ($cvalue =~ m/^([^:]+):/) {
6357 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
6360 foreach my $id (keys %$data) {
6361 foreach my $item (@{$data->{$id}}) {
6362 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
6363 push @$res, $item->{volid
} if defined($item->{volid
});
6370 my $complete_vmid_full = sub {
6373 my $idlist = vmstatus
();
6377 foreach my $id (keys %$idlist) {
6378 my $d = $idlist->{$id};
6379 if (defined($running)) {
6380 next if $d->{template
};
6381 next if $running && $d->{status
} ne 'running';
6382 next if !$running && $d->{status
} eq 'running';
6391 return &$complete_vmid_full();
6394 sub complete_vmid_stopped
{
6395 return &$complete_vmid_full(0);
6398 sub complete_vmid_running
{
6399 return &$complete_vmid_full(1);
6402 sub complete_storage
{
6404 my $cfg = PVE
::Storage
::config
();
6405 my $ids = $cfg->{ids
};
6408 foreach my $sid (keys %$ids) {
6409 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
6410 next if !$ids->{$sid}->{content
}->{images
};
6420 vm_mon_cmd
($vmid, 'nbd-server-stop');