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 pattern
=> '[^,;]+',
1005 format_description
=> 'string',
1006 description
=> "Custom pci device rom filename (must be located in /usr/share/kvm/).",
1011 description
=> "Choose the PCI-express bus (needs the 'q35' machine model).",
1017 description
=> "Enable vfio-vga device support.",
1022 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', $hostpci_fmt);
1026 type
=> 'string', format
=> 'pve-qm-hostpci',
1027 description
=> "Map host PCI devices into guest.",
1028 verbose_description
=> <<EODESCR,
1029 Map host PCI devices into guest.
1031 NOTE: This option allows direct access to host hardware. So it is no longer
1032 possible to migrate such machines - use with special care.
1034 CAUTION: Experimental! User reported problems with this option.
1037 PVE
::JSONSchema
::register_standard_option
("pve-qm-hostpci", $hostpcidesc);
1042 pattern
=> '(/dev/.+|socket)',
1043 description
=> "Create a serial device inside the VM (n is 0 to 3)",
1044 verbose_description
=> <<EODESCR,
1045 Create a serial device inside the VM (n is 0 to 3), and pass through a
1046 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
1047 host side (use 'qm terminal' to open a terminal connection).
1049 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
1051 CAUTION: Experimental! User reported problems with this option.
1058 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1059 description
=> "Map host parallel devices (n is 0 to 2).",
1060 verbose_description
=> <<EODESCR,
1061 Map host parallel devices (n is 0 to 2).
1063 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1065 CAUTION: Experimental! User reported problems with this option.
1069 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1070 $confdesc->{"parallel$i"} = $paralleldesc;
1073 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1074 $confdesc->{"serial$i"} = $serialdesc;
1077 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
1078 $confdesc->{"hostpci$i"} = $hostpcidesc;
1081 for (my $i = 0; $i < $MAX_IDE_DISKS; $i++) {
1082 $drivename_hash->{"ide$i"} = 1;
1083 $confdesc->{"ide$i"} = $idedesc;
1086 for (my $i = 0; $i < $MAX_SATA_DISKS; $i++) {
1087 $drivename_hash->{"sata$i"} = 1;
1088 $confdesc->{"sata$i"} = $satadesc;
1091 for (my $i = 0; $i < $MAX_SCSI_DISKS; $i++) {
1092 $drivename_hash->{"scsi$i"} = 1;
1093 $confdesc->{"scsi$i"} = $scsidesc ;
1096 for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++) {
1097 $drivename_hash->{"virtio$i"} = 1;
1098 $confdesc->{"virtio$i"} = $virtiodesc;
1101 $drivename_hash->{efidisk0
} = 1;
1102 $confdesc->{efidisk0
} = $efidisk_desc;
1104 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1105 $confdesc->{"usb$i"} = $usbdesc;
1110 type
=> 'string', format
=> 'pve-volume-id',
1111 description
=> "Reference to unused volumes. This is used internally, and should not be modified manually.",
1114 for (my $i = 0; $i < $MAX_UNUSED_DISKS; $i++) {
1115 $confdesc->{"unused$i"} = $unuseddesc;
1118 my $kvm_api_version = 0;
1122 return $kvm_api_version if $kvm_api_version;
1124 my $fh = IO
::File-
>new("</dev/kvm") ||
1127 if (my $v = $fh->ioctl(KVM_GET_API_VERSION
(), 0)) {
1128 $kvm_api_version = $v;
1133 return $kvm_api_version;
1136 my $kvm_user_version;
1138 sub kvm_user_version
{
1140 return $kvm_user_version if $kvm_user_version;
1142 $kvm_user_version = 'unknown';
1146 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1147 $kvm_user_version = $2;
1151 eval { run_command
("kvm -version", outfunc
=> $code); };
1154 return $kvm_user_version;
1158 my $kernel_has_vhost_net = -c
'/dev/vhost-net';
1160 sub valid_drive_names
{
1161 # order is important - used to autoselect boot disk
1162 return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
1163 (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
1164 (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))),
1165 (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))),
1169 sub is_valid_drivename
{
1172 return defined($drivename_hash->{$dev});
1177 return defined($confdesc->{$key});
1181 return $nic_model_list;
1184 sub os_list_description
{
1188 wxp
=> 'Windows XP',
1189 w2k
=> 'Windows 2000',
1190 w2k3
=>, 'Windows 2003',
1191 w2k8
=> 'Windows 2008',
1192 wvista
=> 'Windows Vista',
1193 win7
=> 'Windows 7',
1194 win8
=> 'Windows 8/2012',
1195 win10
=> 'Windows 10/2016',
1203 sub get_cdrom_path
{
1205 return $cdrom_path if $cdrom_path;
1207 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1208 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1209 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1213 my ($storecfg, $vmid, $cdrom) = @_;
1215 if ($cdrom eq 'cdrom') {
1216 return get_cdrom_path
();
1217 } elsif ($cdrom eq 'none') {
1219 } elsif ($cdrom =~ m
|^/|) {
1222 return PVE
::Storage
::path
($storecfg, $cdrom);
1226 # try to convert old style file names to volume IDs
1227 sub filename_to_volume_id
{
1228 my ($vmid, $file, $media) = @_;
1230 if (!($file eq 'none' || $file eq 'cdrom' ||
1231 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1233 return undef if $file =~ m
|/|;
1235 if ($media && $media eq 'cdrom') {
1236 $file = "local:iso/$file";
1238 $file = "local:$vmid/$file";
1245 sub verify_media_type
{
1246 my ($opt, $vtype, $media) = @_;
1251 if ($media eq 'disk') {
1253 } elsif ($media eq 'cdrom') {
1256 die "internal error";
1259 return if ($vtype eq $etype);
1261 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1264 sub cleanup_drive_path
{
1265 my ($opt, $storecfg, $drive) = @_;
1267 # try to convert filesystem paths to volume IDs
1269 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1270 ($drive->{file
} !~ m
|^/dev/.+|) &&
1271 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1272 ($drive->{file
} !~ m/^\d+$/)) {
1273 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1274 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1275 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1276 verify_media_type
($opt, $vtype, $drive->{media
});
1277 $drive->{file
} = $volid;
1280 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1283 sub parse_hotplug_features
{
1288 return $res if $data eq '0';
1290 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1292 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1293 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1296 die "invalid hotplug feature '$feature'\n";
1302 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1303 sub pve_verify_hotplug_features
{
1304 my ($value, $noerr) = @_;
1306 return $value if parse_hotplug_features
($value);
1308 return undef if $noerr;
1310 die "unable to parse hotplug option\n";
1313 # ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
1314 # [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
1315 # [,rerror=ignore|report|stop][,werror=enospc|ignore|report|stop]
1316 # [,aio=native|threads][,discard=ignore|on][,detect_zeroes=on|off]
1317 # [,iothread=on][,serial=serial][,model=model]
1320 my ($key, $data) = @_;
1322 my ($interface, $index);
1324 if ($key =~ m/^([^\d]+)(\d+)$/) {
1331 my $desc = $key =~ /^unused\d+$/ ?
$alldrive_fmt
1332 : $confdesc->{$key}->{format
};
1334 warn "invalid drive key: $key\n";
1337 my $res = eval { PVE
::JSONSchema
::parse_property_string
($desc, $data) };
1338 return undef if !$res;
1339 $res->{interface
} = $interface;
1340 $res->{index} = $index;
1343 foreach my $opt (qw(bps bps_rd bps_wr)) {
1344 if (my $bps = defined(delete $res->{$opt})) {
1345 if (defined($res->{"m$opt"})) {
1346 warn "both $opt and m$opt specified\n";
1350 $res->{"m$opt"} = sprintf("%.3f", $bps / (1024*1024.0));
1354 # can't use the schema's 'requires' because of the mbps* => bps* "transforming aliases"
1355 for my $requirement (
1356 [bps_max_length
=> 'mbps_max'],
1357 [bps_rd_max_length
=> 'mbps_rd_max'],
1358 [bps_wr_max_length
=> 'mbps_wr_max'],
1359 [iops_max_length
=> 'iops_max'],
1360 [iops_rd_max_length
=> 'iops_rd_max'],
1361 [iops_wr_max_length
=> 'iops_wr_max']) {
1362 my ($option, $requires) = @$requirement;
1363 if ($res->{$option} && !$res->{$requires}) {
1364 warn "$option requires $requires\n";
1369 return undef if $error;
1371 return undef if $res->{mbps_rd
} && $res->{mbps
};
1372 return undef if $res->{mbps_wr
} && $res->{mbps
};
1373 return undef if $res->{iops_rd
} && $res->{iops
};
1374 return undef if $res->{iops_wr
} && $res->{iops
};
1376 if ($res->{media
} && ($res->{media
} eq 'cdrom')) {
1377 return undef if $res->{snapshot
} || $res->{trans
} || $res->{format
};
1378 return undef if $res->{heads
} || $res->{secs
} || $res->{cyls
};
1379 return undef if $res->{interface
} eq 'virtio';
1382 if (my $size = $res->{size
}) {
1383 return undef if !defined($res->{size
} = PVE
::JSONSchema
::parse_size
($size));
1390 my ($vmid, $drive) = @_;
1391 my $data = { %$drive };
1392 delete $data->{$_} for qw(index interface);
1393 return PVE
::JSONSchema
::print_property_string
($data, $alldrive_fmt);
1397 my($fh, $noerr) = @_;
1400 my $SG_GET_VERSION_NUM = 0x2282;
1402 my $versionbuf = "\x00" x
8;
1403 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1405 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1408 my $version = unpack("I", $versionbuf);
1409 if ($version < 30000) {
1410 die "scsi generic interface too old\n" if !$noerr;
1414 my $buf = "\x00" x
36;
1415 my $sensebuf = "\x00" x
8;
1416 my $cmd = pack("C x3 C x1", 0x12, 36);
1418 # see /usr/include/scsi/sg.h
1419 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";
1421 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1422 length($sensebuf), 0, length($buf), $buf,
1423 $cmd, $sensebuf, 6000);
1425 $ret = ioctl($fh, $SG_IO, $packet);
1427 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1431 my @res = unpack($sg_io_hdr_t, $packet);
1432 if ($res[17] || $res[18]) {
1433 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1438 (my $byte0, my $byte1, $res->{vendor
},
1439 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1441 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1442 $res->{type
} = $byte0 & 31;
1450 my $fh = IO
::File-
>new("+<$path") || return undef;
1451 my $res = scsi_inquiry
($fh, 1);
1457 sub machine_type_is_q35
{
1460 return $conf->{machine
} && ($conf->{machine
} =~ m/q35/) ?
1 : 0;
1463 sub print_tabletdevice_full
{
1466 my $q35 = machine_type_is_q35
($conf);
1468 # we use uhci for old VMs because tablet driver was buggy in older qemu
1469 my $usbbus = $q35 ?
"ehci" : "uhci";
1471 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1474 sub print_drivedevice_full
{
1475 my ($storecfg, $conf, $vmid, $drive, $bridges) = @_;
1480 if ($drive->{interface
} eq 'virtio') {
1481 my $pciaddr = print_pci_addr
("$drive->{interface}$drive->{index}", $bridges);
1482 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1483 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread
};
1484 } elsif ($drive->{interface
} eq 'scsi') {
1486 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1487 my $unit = $drive->{index} % $maxdev;
1488 my $devicetype = 'hd';
1490 if (drive_is_cdrom
($drive)) {
1493 if ($drive->{file
} =~ m
|^/|) {
1494 $path = $drive->{file
};
1495 if (my $info = path_is_scsi
($path)) {
1496 if ($info->{type
} == 0) {
1497 $devicetype = 'block';
1498 } elsif ($info->{type
} == 1) { # tape
1499 $devicetype = 'generic';
1503 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1506 if($path =~ m/^iscsi\:\/\
//){
1507 $devicetype = 'generic';
1511 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1512 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1514 $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}";
1517 } elsif ($drive->{interface
} eq 'ide'){
1519 my $controller = int($drive->{index} / $maxdev);
1520 my $unit = $drive->{index} % $maxdev;
1521 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1523 $device = "ide-$devicetype,bus=ide.$controller,unit=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1524 if ($devicetype eq 'hd' && (my $model = $drive->{model
})) {
1525 $model = URI
::Escape
::uri_unescape
($model);
1526 $device .= ",model=$model";
1528 } elsif ($drive->{interface
} eq 'sata'){
1529 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
1530 my $unit = $drive->{index} % $MAX_SATA_DISKS;
1531 $device = "ide-drive,bus=ahci$controller.$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1532 } elsif ($drive->{interface
} eq 'usb') {
1534 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1536 die "unsupported interface type";
1539 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1544 sub get_initiator_name
{
1547 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return undef;
1548 while (defined(my $line = <$fh>)) {
1549 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1558 sub print_drive_full
{
1559 my ($storecfg, $vmid, $drive) = @_;
1562 my $volid = $drive->{file
};
1565 if (drive_is_cdrom
($drive)) {
1566 $path = get_iso_path
($storecfg, $vmid, $volid);
1568 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1570 $path = PVE
::Storage
::path
($storecfg, $volid);
1571 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1572 $format = qemu_img_format
($scfg, $volname);
1580 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);
1581 foreach my $o (@qemu_drive_options) {
1582 $opts .= ",$o=$drive->{$o}" if $drive->{$o};
1584 if (my $serial = $drive->{serial
}) {
1585 $serial = URI
::Escape
::uri_unescape
($serial);
1586 $opts .= ",serial=$serial";
1589 $opts .= ",format=$format" if $format && !$drive->{format
};
1591 foreach my $o (qw(bps bps_rd bps_wr)) {
1592 my $v = $drive->{"m$o"};
1593 $opts .= ",$o=" . int($v*1024*1024) if $v;
1596 my $cache_direct = 0;
1598 if (my $cache = $drive->{cache
}) {
1599 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1600 } elsif (!drive_is_cdrom
($drive)) {
1601 $opts .= ",cache=none";
1605 # aio native works only with O_DIRECT
1606 if (!$drive->{aio
}) {
1608 $opts .= ",aio=native";
1610 $opts .= ",aio=threads";
1614 if (!drive_is_cdrom
($drive)) {
1616 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1617 $detectzeroes = 'off';
1618 } elsif ($drive->{discard
}) {
1619 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1621 # This used to be our default with discard not being specified:
1622 $detectzeroes = 'on';
1624 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1627 my $pathinfo = $path ?
"file=$path," : '';
1629 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1632 sub print_netdevice_full
{
1633 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files) = @_;
1635 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
1637 my $device = $net->{model
};
1638 if ($net->{model
} eq 'virtio') {
1639 $device = 'virtio-net-pci';
1642 my $pciaddr = print_pci_addr
("$netid", $bridges);
1643 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1644 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1645 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1646 my $vectors = $net->{queues
} * 2 + 2;
1647 $tmpstr .= ",vectors=$vectors,mq=on";
1649 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1651 if ($use_old_bios_files) {
1653 if ($device eq 'virtio-net-pci') {
1654 $romfile = 'pxe-virtio.rom';
1655 } elsif ($device eq 'e1000') {
1656 $romfile = 'pxe-e1000.rom';
1657 } elsif ($device eq 'ne2k') {
1658 $romfile = 'pxe-ne2k_pci.rom';
1659 } elsif ($device eq 'pcnet') {
1660 $romfile = 'pxe-pcnet.rom';
1661 } elsif ($device eq 'rtl8139') {
1662 $romfile = 'pxe-rtl8139.rom';
1664 $tmpstr .= ",romfile=$romfile" if $romfile;
1670 sub print_netdev_full
{
1671 my ($vmid, $conf, $net, $netid, $hotplug) = @_;
1674 if ($netid =~ m/^net(\d+)$/) {
1678 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1680 my $ifname = "tap${vmid}i$i";
1682 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1683 die "interface name '$ifname' is too long (max 15 character)\n"
1684 if length($ifname) >= 16;
1686 my $vhostparam = '';
1687 $vhostparam = ',vhost=on' if $kernel_has_vhost_net && $net->{model
} eq 'virtio';
1689 my $vmname = $conf->{name
} || "vm$vmid";
1692 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1694 if ($net->{bridge
}) {
1695 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1697 $netdev = "type=user,id=$netid,hostname=$vmname";
1700 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1706 sub print_cpu_device
{
1707 my ($conf, $id) = @_;
1709 my $nokvm = defined($conf->{kvm
}) && $conf->{kvm
} == 0 ?
1 : 0;
1710 my $cpu = $nokvm ?
"qemu64" : "kvm64";
1711 if (my $cputype = $conf->{cpu
}) {
1712 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
1713 or die "Cannot parse cpu description: $cputype\n";
1714 $cpu = $cpuconf->{cputype
};
1718 $sockets = $conf->{sockets
} if $conf->{sockets
};
1719 my $cores = $conf->{cores
} || 1;
1721 my $current_core = ($id - 1) % $cores;
1722 my $current_socket = int(($id - $current_core)/$cores);
1724 return "$cpu-x86_64-cpu,id=cpu$id,socket-id=$current_socket,core-id=$current_core,thread-id=0";
1727 sub drive_is_cdrom
{
1730 return $drive && $drive->{media
} && ($drive->{media
} eq 'cdrom');
1734 sub parse_number_sets
{
1737 foreach my $part (split(/;/, $set)) {
1738 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
1739 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
1740 push @$res, [ $1, $2 ];
1742 die "invalid range: $part\n";
1751 my $res = PVE
::JSONSchema
::parse_property_string
($numa_fmt, $data);
1752 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
1753 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
1760 return undef if !$value;
1762 my $res = PVE
::JSONSchema
::parse_property_string
($hostpci_fmt, $value);
1764 my @idlist = split(/;/, $res->{host
});
1765 delete $res->{host
};
1766 foreach my $id (@idlist) {
1767 if ($id =~ /^$PCIRE$/) {
1769 push @{$res->{pciid
}}, { id
=> $1, function
=> $2 };
1771 my $pcidevices = lspci
($1);
1772 $res->{pciid
} = $pcidevices->{$1};
1775 # should have been caught by parse_property_string already
1776 die "failed to parse PCI id: $id\n";
1782 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1786 my $res = eval { PVE
::JSONSchema
::parse_property_string
($net_fmt, $data) };
1791 if (!defined($res->{macaddr
})) {
1792 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
1793 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
1801 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
1804 sub add_random_macs
{
1805 my ($settings) = @_;
1807 foreach my $opt (keys %$settings) {
1808 next if $opt !~ m/^net(\d+)$/;
1809 my $net = parse_net
($settings->{$opt});
1811 $settings->{$opt} = print_net
($net);
1815 sub vm_is_volid_owner
{
1816 my ($storecfg, $vmid, $volid) = @_;
1818 if ($volid !~ m
|^/|) {
1820 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
1821 if ($owner && ($owner == $vmid)) {
1829 sub split_flagged_list
{
1830 my $text = shift || '';
1831 $text =~ s/[,;]/ /g;
1833 return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
1836 sub join_flagged_list
{
1837 my ($how, $lst) = @_;
1838 join $how, map { $lst->{$_} . $_ } keys %$lst;
1841 sub vmconfig_delete_pending_option
{
1842 my ($conf, $key, $force) = @_;
1844 delete $conf->{pending
}->{$key};
1845 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
1846 $pending_delete_hash->{$key} = $force ?
'!' : '';
1847 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
1850 sub vmconfig_undelete_pending_option
{
1851 my ($conf, $key) = @_;
1853 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
1854 delete $pending_delete_hash->{$key};
1856 if (%$pending_delete_hash) {
1857 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
1859 delete $conf->{pending
}->{delete};
1863 sub vmconfig_register_unused_drive
{
1864 my ($storecfg, $vmid, $conf, $drive) = @_;
1866 if (!drive_is_cdrom
($drive)) {
1867 my $volid = $drive->{file
};
1868 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
1869 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
1874 sub vmconfig_cleanup_pending
{
1877 # remove pending changes when nothing changed
1879 foreach my $opt (keys %{$conf->{pending
}}) {
1880 if (defined($conf->{$opt}) && ($conf->{pending
}->{$opt} eq $conf->{$opt})) {
1882 delete $conf->{pending
}->{$opt};
1886 my $current_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
1887 my $pending_delete_hash = {};
1888 while (my ($opt, $force) = each %$current_delete_hash) {
1889 if (defined($conf->{$opt})) {
1890 $pending_delete_hash->{$opt} = $force;
1896 if (%$pending_delete_hash) {
1897 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
1899 delete $conf->{pending
}->{delete};
1905 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
1909 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
1910 format_description
=> 'UUID',
1911 description
=> "Set SMBIOS1 UUID.",
1917 format_description
=> 'string',
1918 description
=> "Set SMBIOS1 version.",
1924 format_description
=> 'string',
1925 description
=> "Set SMBIOS1 serial number.",
1931 format_description
=> 'string',
1932 description
=> "Set SMBIOS1 manufacturer.",
1938 format_description
=> 'string',
1939 description
=> "Set SMBIOS1 product ID.",
1945 format_description
=> 'string',
1946 description
=> "Set SMBIOS1 SKU string.",
1952 format_description
=> 'string',
1953 description
=> "Set SMBIOS1 family string.",
1961 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_fmt, $data) };
1968 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
1971 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
1973 PVE
::JSONSchema
::register_format
('pve-qm-bootdisk', \
&verify_bootdisk
);
1974 sub verify_bootdisk
{
1975 my ($value, $noerr) = @_;
1977 return $value if is_valid_drivename
($value);
1979 return undef if $noerr;
1981 die "invalid boot disk '$value'\n";
1984 sub parse_watchdog
{
1987 return undef if !$value;
1989 my $res = eval { PVE
::JSONSchema
::parse_property_string
($watchdog_fmt, $value) };
1994 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
1995 sub verify_usb_device
{
1996 my ($value, $noerr) = @_;
1998 return $value if parse_usb_device
($value);
2000 return undef if $noerr;
2002 die "unable to parse usb device\n";
2005 # add JSON properties for create and set function
2006 sub json_config_properties
{
2009 foreach my $opt (keys %$confdesc) {
2010 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate';
2011 $prop->{$opt} = $confdesc->{$opt};
2018 my ($key, $value) = @_;
2020 die "unknown setting '$key'\n" if !$confdesc->{$key};
2022 my $type = $confdesc->{$key}->{type
};
2024 if (!defined($value)) {
2025 die "got undefined value\n";
2028 if ($value =~ m/[\n\r]/) {
2029 die "property contains a line feed\n";
2032 if ($type eq 'boolean') {
2033 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
2034 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
2035 die "type check ('boolean') failed - got '$value'\n";
2036 } elsif ($type eq 'integer') {
2037 return int($1) if $value =~ m/^(\d+)$/;
2038 die "type check ('integer') failed - got '$value'\n";
2039 } elsif ($type eq 'number') {
2040 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
2041 die "type check ('number') failed - got '$value'\n";
2042 } elsif ($type eq 'string') {
2043 if (my $fmt = $confdesc->{$key}->{format
}) {
2044 PVE
::JSONSchema
::check_format
($fmt, $value);
2047 $value =~ s/^\"(.*)\"$/$1/;
2050 die "internal error"
2054 sub check_iommu_support
{
2055 #fixme : need to check IOMMU support
2056 #http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM
2066 my $conf = PVE
::QemuConfig-
>config_file($vmid);
2067 utime undef, undef, $conf;
2071 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
2073 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
2075 my $conf = PVE
::QemuConfig-
>load_config($vmid);
2077 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
2079 # only remove disks owned by this VM
2080 foreach_drive
($conf, sub {
2081 my ($ds, $drive) = @_;
2083 return if drive_is_cdrom
($drive);
2085 my $volid = $drive->{file
};
2087 return if !$volid || $volid =~ m
|^/|;
2089 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2090 return if !$path || !$owner || ($owner != $vmid);
2093 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2095 warn "Could not remove disk '$volid', check manually: $@" if $@;
2099 if ($keep_empty_config) {
2100 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
2105 # also remove unused disk
2107 my $dl = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
2110 PVE
::Storage
::foreach_volid
($dl, sub {
2111 my ($volid, $sid, $volname, $d) = @_;
2112 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2121 sub parse_vm_config
{
2122 my ($filename, $raw) = @_;
2124 return undef if !defined($raw);
2127 digest
=> Digest
::SHA
::sha1_hex
($raw),
2132 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2133 || die "got strange filename '$filename'";
2141 my @lines = split(/\n/, $raw);
2142 foreach my $line (@lines) {
2143 next if $line =~ m/^\s*$/;
2145 if ($line =~ m/^\[PENDING\]\s*$/i) {
2146 $section = 'pending';
2147 if (defined($descr)) {
2149 $conf->{description
} = $descr;
2152 $conf = $res->{$section} = {};
2155 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2157 if (defined($descr)) {
2159 $conf->{description
} = $descr;
2162 $conf = $res->{snapshots
}->{$section} = {};
2166 if ($line =~ m/^\#(.*)\s*$/) {
2167 $descr = '' if !defined($descr);
2168 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2172 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2173 $descr = '' if !defined($descr);
2174 $descr .= PVE
::Tools
::decode_text
($2);
2175 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2176 $conf->{snapstate
} = $1;
2177 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2180 $conf->{$key} = $value;
2181 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2183 if ($section eq 'pending') {
2184 $conf->{delete} = $value; # we parse this later
2186 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2188 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(\S+)\s*$/) {
2191 eval { $value = check_type
($key, $value); };
2193 warn "vm $vmid - unable to parse value of '$key' - $@";
2195 $key = 'ide2' if $key eq 'cdrom';
2196 my $fmt = $confdesc->{$key}->{format
};
2197 if ($fmt && $fmt =~ /^pve-qm-(?:ide|scsi|virtio|sata)$/) {
2198 my $v = parse_drive
($key, $value);
2199 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2200 $v->{file
} = $volid;
2201 $value = print_drive
($vmid, $v);
2203 warn "vm $vmid - unable to parse value of '$key'\n";
2208 $conf->{$key} = $value;
2213 if (defined($descr)) {
2215 $conf->{description
} = $descr;
2217 delete $res->{snapstate
}; # just to be sure
2222 sub write_vm_config
{
2223 my ($filename, $conf) = @_;
2225 delete $conf->{snapstate
}; # just to be sure
2227 if ($conf->{cdrom
}) {
2228 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2229 $conf->{ide2
} = $conf->{cdrom
};
2230 delete $conf->{cdrom
};
2233 # we do not use 'smp' any longer
2234 if ($conf->{sockets
}) {
2235 delete $conf->{smp
};
2236 } elsif ($conf->{smp
}) {
2237 $conf->{sockets
} = $conf->{smp
};
2238 delete $conf->{cores
};
2239 delete $conf->{smp
};
2242 my $used_volids = {};
2244 my $cleanup_config = sub {
2245 my ($cref, $pending, $snapname) = @_;
2247 foreach my $key (keys %$cref) {
2248 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2249 $key eq 'snapstate' || $key eq 'pending';
2250 my $value = $cref->{$key};
2251 if ($key eq 'delete') {
2252 die "propertry 'delete' is only allowed in [PENDING]\n"
2254 # fixme: check syntax?
2257 eval { $value = check_type
($key, $value); };
2258 die "unable to parse value of '$key' - $@" if $@;
2260 $cref->{$key} = $value;
2262 if (!$snapname && is_valid_drivename
($key)) {
2263 my $drive = parse_drive
($key, $value);
2264 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2269 &$cleanup_config($conf);
2271 &$cleanup_config($conf->{pending
}, 1);
2273 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2274 die "internal error" if $snapname eq 'pending';
2275 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2278 # remove 'unusedX' settings if we re-add a volume
2279 foreach my $key (keys %$conf) {
2280 my $value = $conf->{$key};
2281 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2282 delete $conf->{$key};
2286 my $generate_raw_config = sub {
2287 my ($conf, $pending) = @_;
2291 # add description as comment to top of file
2292 if (defined(my $descr = $conf->{description
})) {
2294 foreach my $cl (split(/\n/, $descr)) {
2295 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2298 $raw .= "#\n" if $pending;
2302 foreach my $key (sort keys %$conf) {
2303 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2304 $raw .= "$key: $conf->{$key}\n";
2309 my $raw = &$generate_raw_config($conf);
2311 if (scalar(keys %{$conf->{pending
}})){
2312 $raw .= "\n[PENDING]\n";
2313 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2316 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2317 $raw .= "\n[$snapname]\n";
2318 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2328 # we use static defaults from our JSON schema configuration
2329 foreach my $key (keys %$confdesc) {
2330 if (defined(my $default = $confdesc->{$key}->{default})) {
2331 $res->{$key} = $default;
2335 my $conf = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
2336 $res->{keyboard
} = $conf->{keyboard
} if $conf->{keyboard
};
2342 my $vmlist = PVE
::Cluster
::get_vmlist
();
2344 return $res if !$vmlist || !$vmlist->{ids
};
2345 my $ids = $vmlist->{ids
};
2347 foreach my $vmid (keys %$ids) {
2348 my $d = $ids->{$vmid};
2349 next if !$d->{node
} || $d->{node
} ne $nodename;
2350 next if !$d->{type
} || $d->{type
} ne 'qemu';
2351 $res->{$vmid}->{exists} = 1;
2356 # test if VM uses local resources (to prevent migration)
2357 sub check_local_resources
{
2358 my ($conf, $noerr) = @_;
2362 $loc_res = 1 if $conf->{hostusb
}; # old syntax
2363 $loc_res = 1 if $conf->{hostpci
}; # old syntax
2365 foreach my $k (keys %$conf) {
2366 next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2367 # sockets are safe: they will recreated be on the target side post-migrate
2368 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2369 $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2372 die "VM uses local resources\n" if $loc_res && !$noerr;
2377 # check if used storages are available on all nodes (use by migrate)
2378 sub check_storage_availability
{
2379 my ($storecfg, $conf, $node) = @_;
2381 foreach_drive
($conf, sub {
2382 my ($ds, $drive) = @_;
2384 my $volid = $drive->{file
};
2387 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2390 # check if storage is available on both nodes
2391 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2392 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2396 # list nodes where all VM images are available (used by has_feature API)
2398 my ($conf, $storecfg) = @_;
2400 my $nodelist = PVE
::Cluster
::get_nodelist
();
2401 my $nodehash = { map { $_ => 1 } @$nodelist };
2402 my $nodename = PVE
::INotify
::nodename
();
2404 foreach_drive
($conf, sub {
2405 my ($ds, $drive) = @_;
2407 my $volid = $drive->{file
};
2410 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2412 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2413 if ($scfg->{disable
}) {
2415 } elsif (my $avail = $scfg->{nodes
}) {
2416 foreach my $node (keys %$nodehash) {
2417 delete $nodehash->{$node} if !$avail->{$node};
2419 } elsif (!$scfg->{shared
}) {
2420 foreach my $node (keys %$nodehash) {
2421 delete $nodehash->{$node} if $node ne $nodename
2431 my ($pidfile, $pid) = @_;
2433 my $fh = IO
::File-
>new("/proc/$pid/cmdline", "r");
2437 return undef if !$line;
2438 my @param = split(/\0/, $line);
2440 my $cmd = $param[0];
2441 return if !$cmd || ($cmd !~ m
|kvm
$| && $cmd !~ m
|qemu-system-x86_64
$|);
2443 for (my $i = 0; $i < scalar (@param); $i++) {
2446 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2447 my $p = $param[$i+1];
2448 return 1 if $p && ($p eq $pidfile);
2457 my ($vmid, $nocheck, $node) = @_;
2459 my $filename = PVE
::QemuConfig-
>config_file($vmid, $node);
2461 die "unable to find configuration file for VM $vmid - no such machine\n"
2462 if !$nocheck && ! -f
$filename;
2464 my $pidfile = pidfile_name
($vmid);
2466 if (my $fd = IO
::File-
>new("<$pidfile")) {
2471 my $mtime = $st->mtime;
2472 if ($mtime > time()) {
2473 warn "file '$filename' modified in future\n";
2476 if ($line =~ m/^(\d+)$/) {
2478 if (check_cmdline
($pidfile, $pid)) {
2479 if (my $pinfo = PVE
::ProcFSTools
::check_process_running
($pid)) {
2491 my $vzlist = config_list
();
2493 my $fd = IO
::Dir-
>new($var_run_tmpdir) || return $vzlist;
2495 while (defined(my $de = $fd->read)) {
2496 next if $de !~ m/^(\d+)\.pid$/;
2498 next if !defined($vzlist->{$vmid});
2499 if (my $pid = check_running
($vmid)) {
2500 $vzlist->{$vmid}->{pid
} = $pid;
2508 my ($storecfg, $conf) = @_;
2510 my $bootdisk = $conf->{bootdisk
};
2511 return undef if !$bootdisk;
2512 return undef if !is_valid_drivename
($bootdisk);
2514 return undef if !$conf->{$bootdisk};
2516 my $drive = parse_drive
($bootdisk, $conf->{$bootdisk});
2517 return undef if !defined($drive);
2519 return undef if drive_is_cdrom
($drive);
2521 my $volid = $drive->{file
};
2522 return undef if !$volid;
2524 return $drive->{size
};
2527 my $last_proc_pid_stat;
2529 # get VM status information
2530 # This must be fast and should not block ($full == false)
2531 # We only query KVM using QMP if $full == true (this can be slow)
2533 my ($opt_vmid, $full) = @_;
2537 my $storecfg = PVE
::Storage
::config
();
2539 my $list = vzlist
();
2540 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2542 my $cpucount = $cpuinfo->{cpus
} || 1;
2544 foreach my $vmid (keys %$list) {
2545 next if $opt_vmid && ($vmid ne $opt_vmid);
2547 my $cfspath = PVE
::QemuConfig-
>cfs_config_path($vmid);
2548 my $conf = PVE
::Cluster
::cfs_read_file
($cfspath) || {};
2551 $d->{pid
} = $list->{$vmid}->{pid
};
2553 # fixme: better status?
2554 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
2556 my $size = disksize
($storecfg, $conf);
2557 if (defined($size)) {
2558 $d->{disk
} = 0; # no info available
2559 $d->{maxdisk
} = $size;
2565 $d->{cpus
} = ($conf->{sockets
} || 1) * ($conf->{cores
} || 1);
2566 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
2567 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
2569 $d->{name
} = $conf->{name
} || "VM $vmid";
2570 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024) : 0;
2572 if ($conf->{balloon
}) {
2573 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
2574 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
} : 1000;
2585 $d->{diskwrite
} = 0;
2587 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
2592 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
2593 foreach my $dev (keys %$netdev) {
2594 next if $dev !~ m/^tap([1-9]\d*)i/;
2596 my $d = $res->{$vmid};
2599 $d->{netout
} += $netdev->{$dev}->{receive
};
2600 $d->{netin
} += $netdev->{$dev}->{transmit
};
2603 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
2604 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
2609 my $ctime = gettimeofday
;
2611 foreach my $vmid (keys %$list) {
2613 my $d = $res->{$vmid};
2614 my $pid = $d->{pid
};
2617 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
2618 next if !$pstat; # not running
2620 my $used = $pstat->{utime} + $pstat->{stime
};
2622 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
2624 if ($pstat->{vsize
}) {
2625 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
2628 my $old = $last_proc_pid_stat->{$pid};
2630 $last_proc_pid_stat->{$pid} = {
2638 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
2640 if ($dtime > 1000) {
2641 my $dutime = $used - $old->{used
};
2643 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
2644 $last_proc_pid_stat->{$pid} = {
2650 $d->{cpu
} = $old->{cpu
};
2654 return $res if !$full;
2656 my $qmpclient = PVE
::QMPClient-
>new();
2658 my $ballooncb = sub {
2659 my ($vmid, $resp) = @_;
2661 my $info = $resp->{'return'};
2662 return if !$info->{max_mem
};
2664 my $d = $res->{$vmid};
2666 # use memory assigned to VM
2667 $d->{maxmem
} = $info->{max_mem
};
2668 $d->{balloon
} = $info->{actual
};
2670 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
2671 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
2672 $d->{freemem
} = $info->{free_mem
};
2675 $d->{ballooninfo
} = $info;
2678 my $blockstatscb = sub {
2679 my ($vmid, $resp) = @_;
2680 my $data = $resp->{'return'} || [];
2681 my $totalrdbytes = 0;
2682 my $totalwrbytes = 0;
2684 for my $blockstat (@$data) {
2685 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
2686 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
2688 $blockstat->{device
} =~ s/drive-//;
2689 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
2691 $res->{$vmid}->{diskread
} = $totalrdbytes;
2692 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
2695 my $statuscb = sub {
2696 my ($vmid, $resp) = @_;
2698 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
2699 # this fails if ballon driver is not loaded, so this must be
2700 # the last commnand (following command are aborted if this fails).
2701 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
2703 my $status = 'unknown';
2704 if (!defined($status = $resp->{'return'}->{status
})) {
2705 warn "unable to get VM status\n";
2709 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
2712 foreach my $vmid (keys %$list) {
2713 next if $opt_vmid && ($vmid ne $opt_vmid);
2714 next if !$res->{$vmid}->{pid
}; # not running
2715 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
2718 $qmpclient->queue_execute(undef, 2);
2720 foreach my $vmid (keys %$list) {
2721 next if $opt_vmid && ($vmid ne $opt_vmid);
2722 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
2729 my ($conf, $func, @param) = @_;
2731 foreach my $ds (valid_drive_names
()) {
2732 next if !defined($conf->{$ds});
2734 my $drive = parse_drive
($ds, $conf->{$ds});
2737 &$func($ds, $drive, @param);
2742 my ($conf, $func, @param) = @_;
2746 my $test_volid = sub {
2747 my ($volid, $is_cdrom) = @_;
2751 $volhash->{$volid} = $is_cdrom || 0;
2754 foreach_drive
($conf, sub {
2755 my ($ds, $drive) = @_;
2756 &$test_volid($drive->{file
}, drive_is_cdrom
($drive));
2759 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2760 my $snap = $conf->{snapshots
}->{$snapname};
2761 &$test_volid($snap->{vmstate
}, 0);
2762 foreach_drive
($snap, sub {
2763 my ($ds, $drive) = @_;
2764 &$test_volid($drive->{file
}, drive_is_cdrom
($drive));
2768 foreach my $volid (keys %$volhash) {
2769 &$func($volid, $volhash->{$volid}, @param);
2773 sub vga_conf_has_spice
{
2776 return 0 if !$vga || $vga !~ m/^qxl([234])?$/;
2781 sub config_to_command
{
2782 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
2785 my $globalFlags = [];
2786 my $machineFlags = [];
2792 my $kvmver = kvm_user_version
();
2793 my $vernum = 0; # unknown
2794 my $ostype = $conf->{ostype
};
2795 my $winversion = windows_version
($ostype);
2797 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
2798 $vernum = $1*1000000+$2*1000;
2799 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
2800 $vernum = $1*1000000+$2*1000+$3;
2803 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
2805 my $have_ovz = -f
'/proc/vz/vestat';
2807 my $q35 = machine_type_is_q35
($conf);
2808 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
2809 my $machine_type = $forcemachine || $conf->{machine
};
2810 my $use_old_bios_files = undef;
2811 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
2813 my $cpuunits = defined($conf->{cpuunits
}) ?
2814 $conf->{cpuunits
} : $defaults->{cpuunits
};
2816 push @$cmd, '/usr/bin/kvm';
2818 push @$cmd, '-id', $vmid;
2822 my $qmpsocket = qmp_socket
($vmid);
2823 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
2824 push @$cmd, '-mon', "chardev=qmp,mode=control";
2827 push @$cmd, '-pidfile' , pidfile_name
($vmid);
2829 push @$cmd, '-daemonize';
2831 if ($conf->{smbios1
}) {
2832 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
2835 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
2838 # prefer the OVMF_CODE variant
2839 if (-f
$OVMF_CODE) {
2840 $ovmfbase = $OVMF_CODE;
2841 } elsif (-f
$OVMF_IMG) {
2842 $ovmfbase = $OVMF_IMG;
2845 die "no uefi base img found\n" if !$ovmfbase;
2846 push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly,file=$ovmfbase";
2848 if (defined($conf->{efidisk0
}) && ($ovmfbase eq $OVMF_CODE)) {
2849 my $d = PVE
::JSONSchema
::parse_property_string
($efidisk_fmt, $conf->{efidisk0
});
2850 my $format = $d->{format
} // 'raw';
2852 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($d->{file
}, 1);
2854 $path = PVE
::Storage
::path
($storecfg, $d->{file
});
2855 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2856 $format = qemu_img_format
($scfg, $volname);
2861 push @$cmd, '-drive', "if=pflash,unit=1,id=drive-efidisk0,format=$format,file=$path";
2862 } elsif ($ovmfbase eq $OVMF_CODE) {
2863 warn "using uefi without permanent efivars disk\n";
2864 my $ovmfvar_dst = "/tmp/$vmid-ovmf.fd";
2865 PVE
::Tools
::file_copy
($OVMF_VARS, $ovmfvar_dst, 256*1024);
2866 push @$cmd, '-drive', "if=pflash,unit=1,format=raw,file=$ovmfvar_dst";
2868 # if the base img is not OVMF_CODE, we do not have to bother
2869 # to create/use a vars image, since it will not be used anyway
2870 # this can only happen if someone manually deletes the OVMF_CODE image
2871 # or has an old pve-qemu-kvm version installed.
2872 # both should not happen, but we ignore it here
2877 # add usb controllers
2878 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $q35, $usbdesc->{format
}, $MAX_USB_DEVICES);
2879 push @$devices, @usbcontrollers if @usbcontrollers;
2880 my $vga = $conf->{vga
};
2882 my $qxlnum = vga_conf_has_spice
($vga);
2883 $vga = 'qxl' if $qxlnum;
2886 $vga = $winversion >= 6 ?
'std' : 'cirrus';
2889 # enable absolute mouse coordinates (needed by vnc)
2891 if (defined($conf->{tablet
})) {
2892 $tablet = $conf->{tablet
};
2894 $tablet = $defaults->{tablet
};
2895 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
2896 $tablet = 0 if $vga =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
2899 push @$devices, '-device', print_tabletdevice_full
($conf) if $tablet;
2902 my $gpu_passthrough;
2905 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
2906 my $d = parse_hostpci
($conf->{"hostpci$i"});
2909 my $pcie = $d->{pcie
};
2911 die "q35 machine model is not enabled" if !$q35;
2912 $pciaddr = print_pcie_addr
("hostpci$i");
2914 $pciaddr = print_pci_addr
("hostpci$i", $bridges);
2917 my $rombar = defined($d->{rombar
}) && !$d->{rombar
} ?
',rombar=0' : '';
2918 my $romfile = $d->{romfile
};
2921 if ($d->{'x-vga'}) {
2922 $xvga = ',x-vga=on';
2925 $gpu_passthrough = 1;
2927 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
2931 my $pcidevices = $d->{pciid
};
2932 my $multifunction = 1 if @$pcidevices > 1;
2935 foreach my $pcidevice (@$pcidevices) {
2937 my $id = "hostpci$i";
2938 $id .= ".$j" if $multifunction;
2939 my $addr = $pciaddr;
2940 $addr .= ".$j" if $multifunction;
2941 my $devicestr = "vfio-pci,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
2944 $devicestr .= "$rombar$xvga";
2945 $devicestr .= ",multifunction=on" if $multifunction;
2946 $devicestr .= ",romfile=/usr/share/kvm/$romfile" if $romfile;
2949 push @$devices, '-device', $devicestr;
2955 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES);
2956 push @$devices, @usbdevices if @usbdevices;
2958 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
2959 if (my $path = $conf->{"serial$i"}) {
2960 if ($path eq 'socket') {
2961 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
2962 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
2963 push @$devices, '-device', "isa-serial,chardev=serial$i";
2965 die "no such serial device\n" if ! -c
$path;
2966 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
2967 push @$devices, '-device', "isa-serial,chardev=serial$i";
2973 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
2974 if (my $path = $conf->{"parallel$i"}) {
2975 die "no such parallel device\n" if ! -c
$path;
2976 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
2977 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
2978 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
2982 my $vmname = $conf->{name
} || "vm$vmid";
2984 push @$cmd, '-name', $vmname;
2987 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
2988 $sockets = $conf->{sockets
} if $conf->{sockets
};
2990 my $cores = $conf->{cores
} || 1;
2992 my $maxcpus = $sockets * $cores;
2994 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
2996 my $allowed_vcpus = $cpuinfo->{cpus
};
2998 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
2999 if ($allowed_vcpus < $maxcpus);
3001 if($hotplug_features->{cpu
} && qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 7)) {
3003 push @$cmd, '-smp', "1,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3004 for (my $i = 2; $i <= $vcpus; $i++) {
3005 my $cpustr = print_cpu_device
($conf,$i);
3006 push @$cmd, '-device', $cpustr;
3011 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
3013 push @$cmd, '-nodefaults';
3015 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
3017 my $bootindex_hash = {};
3019 foreach my $o (split(//, $bootorder)) {
3020 $bootindex_hash->{$o} = $i*100;
3024 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000,splash=/usr/share/qemu-server/bootsplash.jpg";
3026 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
3028 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
3030 push @$cmd, '-vga', $vga if $vga && $vga !~ m/^serial\d+$/; # for kvm 77 and later
3032 if ($vga && $vga !~ m/^serial\d+$/ && $vga ne 'none'){
3033 my $socket = vnc_socket
($vmid);
3034 push @$cmd, '-vnc', "unix:$socket,x509,password";
3036 push @$cmd, '-nographic';
3040 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
3042 my $nokvm = defined($conf->{kvm
}) && $conf->{kvm
} == 0 ?
1 : 0;
3043 my $useLocaltime = $conf->{localtime};
3045 if ($winversion >= 5) { # windows
3046 $useLocaltime = 1 if !defined($conf->{localtime});
3048 # use time drift fix when acpi is enabled
3049 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
3050 $tdf = 1 if !defined($conf->{tdf
});
3054 if ($winversion >= 6) {
3055 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
3056 push @$cmd, '-no-hpet';
3059 push @$rtcFlags, 'driftfix=slew' if $tdf;
3062 push @$machineFlags, 'accel=tcg';
3064 die "No accelerator found!\n" if !$cpuinfo->{hvm
};
3067 if ($machine_type) {
3068 push @$machineFlags, "type=${machine_type}";
3071 if ($conf->{startdate
}) {
3072 push @$rtcFlags, "base=$conf->{startdate}";
3073 } elsif ($useLocaltime) {
3074 push @$rtcFlags, 'base=localtime';
3077 my $cpu = $nokvm ?
"qemu64" : "kvm64";
3078 if (my $cputype = $conf->{cpu
}) {
3079 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
3080 or die "Cannot parse cpu description: $cputype\n";
3081 $cpu = $cpuconf->{cputype
};
3082 $kvm_off = 1 if $cpuconf->{hidden
};
3085 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64';
3087 push @$cpuFlags , '-x2apic'
3088 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3090 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3092 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3094 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3096 push @$cpuFlags , '+kvm_pv_unhalt' if !$nokvm;
3097 push @$cpuFlags , '+kvm_pv_eoi' if !$nokvm;
3100 add_hyperv_enlighments
($cpuFlags, $winversion, $machine_type, $kvmver, $nokvm, $conf->{bios
}, $gpu_passthrough);
3102 push @$cpuFlags, 'enforce' if $cpu ne 'host' && !$nokvm;
3104 push @$cpuFlags, 'kvm=off' if $kvm_off;
3106 my $cpu_vendor = $cpu_vendor_list->{$cpu} ||
3107 die "internal error"; # should not happen
3109 push @$cpuFlags, "vendor=${cpu_vendor}"
3110 if $cpu_vendor ne 'default';
3112 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3114 push @$cmd, '-cpu', $cpu;
3116 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3118 push @$cmd, '-S' if $conf->{freeze
};
3120 # set keyboard layout
3121 my $kb = $conf->{keyboard
} || $defaults->{keyboard
};
3122 push @$cmd, '-k', $kb if $kb;
3125 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3126 #push @$cmd, '-soundhw', 'es1370';
3127 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3129 if($conf->{agent
}) {
3130 my $qgasocket = qmp_socket
($vmid, 1);
3131 my $pciaddr = print_pci_addr
("qga0", $bridges);
3132 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3133 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3134 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3142 for(my $i = 1; $i < $qxlnum; $i++){
3143 my $pciaddr = print_pci_addr
("vga$i", $bridges);
3144 push @$cmd, '-device', "qxl,id=vga$i,ram_size=67108864,vram_size=33554432$pciaddr";
3147 # assume other OS works like Linux
3148 push @$cmd, '-global', 'qxl-vga.ram_size=134217728';
3149 push @$cmd, '-global', 'qxl-vga.vram_size=67108864';
3153 my $pciaddr = print_pci_addr
("spice", $bridges);
3155 my $nodename = PVE
::INotify
::nodename
();
3156 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3157 $spice_port = PVE
::Tools
::next_spice_port
($pfamily);
3159 push @$devices, '-spice', "tls-port=${spice_port},addr=localhost,tls-ciphers=DES-CBC3-SHA,seamless-migration=on";
3161 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3162 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3163 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3166 # enable balloon by default, unless explicitly disabled
3167 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3168 $pciaddr = print_pci_addr
("balloon0", $bridges);
3169 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3172 if ($conf->{watchdog
}) {
3173 my $wdopts = parse_watchdog
($conf->{watchdog
});
3174 $pciaddr = print_pci_addr
("watchdog", $bridges);
3175 my $watchdog = $wdopts->{model
} || 'i6300esb';
3176 push @$devices, '-device', "$watchdog$pciaddr";
3177 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3181 my $scsicontroller = {};
3182 my $ahcicontroller = {};
3183 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3185 # Add iscsi initiator name if available
3186 if (my $initiator = get_initiator_name
()) {
3187 push @$devices, '-iscsi', "initiator-name=$initiator";
3190 foreach_drive
($conf, sub {
3191 my ($ds, $drive) = @_;
3193 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3194 push @$vollist, $drive->{file
};
3197 $use_virtio = 1 if $ds =~ m/^virtio/;
3199 if (drive_is_cdrom
($drive)) {
3200 if ($bootindex_hash->{d
}) {
3201 $drive->{bootindex
} = $bootindex_hash->{d
};
3202 $bootindex_hash->{d
} += 1;
3205 if ($bootindex_hash->{c
}) {
3206 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3207 $bootindex_hash->{c
} += 1;
3211 if($drive->{interface
} eq 'virtio'){
3212 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3215 if ($drive->{interface
} eq 'scsi') {
3217 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3219 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges);
3220 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3223 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3224 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3225 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3226 } elsif ($drive->{iothread
}) {
3227 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3231 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3232 $queues = ",num_queues=$drive->{queues}";
3235 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3236 $scsicontroller->{$controller}=1;
3239 if ($drive->{interface
} eq 'sata') {
3240 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3241 $pciaddr = print_pci_addr
("ahci$controller", $bridges);
3242 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3243 $ahcicontroller->{$controller}=1;
3246 if ($drive->{interface
} eq 'efidisk') {
3247 # this will be added somewhere else
3251 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3252 push @$devices, '-drive',$drive_cmd;
3253 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges);
3256 for (my $i = 0; $i < $MAX_NETS; $i++) {
3257 next if !$conf->{"net$i"};
3258 my $d = parse_net
($conf->{"net$i"});
3261 $use_virtio = 1 if $d->{model
} eq 'virtio';
3263 if ($bootindex_hash->{n
}) {
3264 $d->{bootindex
} = $bootindex_hash->{n
};
3265 $bootindex_hash->{n
} += 1;
3268 my $netdevfull = print_netdev_full
($vmid,$conf,$d,"net$i");
3269 push @$devices, '-netdev', $netdevfull;
3271 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files);
3272 push @$devices, '-device', $netdevicefull;
3277 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3282 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3284 while (my ($k, $v) = each %$bridges) {
3285 $pciaddr = print_pci_addr
("pci.$k");
3286 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3291 if ($conf->{args
}) {
3292 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3296 push @$cmd, @$devices;
3297 push @$cmd, '-rtc', join(',', @$rtcFlags)
3298 if scalar(@$rtcFlags);
3299 push @$cmd, '-machine', join(',', @$machineFlags)
3300 if scalar(@$machineFlags);
3301 push @$cmd, '-global', join(',', @$globalFlags)
3302 if scalar(@$globalFlags);
3304 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3309 return "${var_run_tmpdir}/$vmid.vnc";
3315 my $res = vm_mon_cmd
($vmid, 'query-spice');
3317 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3321 my ($vmid, $qga) = @_;
3322 my $sockettype = $qga ?
'qga' : 'qmp';
3323 return "${var_run_tmpdir}/$vmid.$sockettype";
3328 return "${var_run_tmpdir}/$vmid.pid";
3331 sub vm_devices_list
{
3334 my $res = vm_mon_cmd
($vmid, 'query-pci');
3336 foreach my $pcibus (@$res) {
3337 foreach my $device (@{$pcibus->{devices
}}) {
3338 next if !$device->{'qdev_id'};
3339 if ($device->{'pci_bridge'}) {
3340 $devices->{$device->{'qdev_id'}} = 1;
3341 foreach my $bridge_device (@{$device->{'pci_bridge'}->{devices
}}) {
3342 next if !$bridge_device->{'qdev_id'};
3343 $devices->{$bridge_device->{'qdev_id'}} = 1;
3344 $devices->{$device->{'qdev_id'}}++;
3347 $devices->{$device->{'qdev_id'}} = 1;
3352 my $resblock = vm_mon_cmd
($vmid, 'query-block');
3353 foreach my $block (@$resblock) {
3354 if($block->{device
} =~ m/^drive-(\S+)/){
3359 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
3360 foreach my $mice (@$resmice) {
3361 if ($mice->{name
} eq 'QEMU HID Tablet') {
3362 $devices->{tablet
} = 1;
3367 # for usb devices there is no query-usb
3368 # but we can iterate over the entries in
3369 # qom-list path=/machine/peripheral
3370 my $resperipheral = vm_mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3371 foreach my $per (@$resperipheral) {
3372 if ($per->{name
} =~ m/^usb\d+$/) {
3373 $devices->{$per->{name
}} = 1;
3381 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
3383 my $q35 = machine_type_is_q35
($conf);
3385 my $devices_list = vm_devices_list
($vmid);
3386 return 1 if defined($devices_list->{$deviceid});
3388 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid); # add PCI bridge if we need it for the device
3390 if ($deviceid eq 'tablet') {
3392 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf));
3394 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3396 die "usb hotplug currently not reliable\n";
3397 # since we can't reliably hot unplug all added usb devices
3398 # and usb passthrough disables live migration
3399 # we disable usb hotplugging for now
3400 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
3402 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3404 qemu_iothread_add
($vmid, $deviceid, $device);
3406 qemu_driveadd
($storecfg, $vmid, $device);
3407 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3409 qemu_deviceadd
($vmid, $devicefull);
3410 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3412 eval { qemu_drivedel
($vmid, $deviceid); };
3417 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3420 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
3421 my $pciaddr = print_pci_addr
($deviceid);
3422 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
3424 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
3426 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
3427 qemu_iothread_add
($vmid, $deviceid, $device);
3428 $devicefull .= ",iothread=iothread-$deviceid";
3431 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
3432 $devicefull .= ",num_queues=$device->{queues}";
3435 qemu_deviceadd
($vmid, $devicefull);
3436 qemu_deviceaddverify
($vmid, $deviceid);
3438 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3440 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device);
3441 qemu_driveadd
($storecfg, $vmid, $device);
3443 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3444 eval { qemu_deviceadd
($vmid, $devicefull); };
3446 eval { qemu_drivedel
($vmid, $deviceid); };
3451 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3453 return undef if !qemu_netdevadd
($vmid, $conf, $device, $deviceid);
3455 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
3456 my $use_old_bios_files = undef;
3457 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3459 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files);
3460 qemu_deviceadd
($vmid, $netdevicefull);
3461 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3463 eval { qemu_netdevdel
($vmid, $deviceid); };
3468 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
3471 my $pciaddr = print_pci_addr
($deviceid);
3472 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
3474 qemu_deviceadd
($vmid, $devicefull);
3475 qemu_deviceaddverify
($vmid, $deviceid);
3478 die "can't hotplug device '$deviceid'\n";
3484 # fixme: this should raise exceptions on error!
3485 sub vm_deviceunplug
{
3486 my ($vmid, $conf, $deviceid) = @_;
3488 my $devices_list = vm_devices_list
($vmid);
3489 return 1 if !defined($devices_list->{$deviceid});
3491 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
3493 if ($deviceid eq 'tablet') {
3495 qemu_devicedel
($vmid, $deviceid);
3497 } elsif ($deviceid =~ m/^usb\d+$/) {
3499 die "usb hotplug currently not reliable\n";
3500 # when unplugging usb devices this way,
3501 # there may be remaining usb controllers/hubs
3502 # so we disable it for now
3503 qemu_devicedel
($vmid, $deviceid);
3504 qemu_devicedelverify
($vmid, $deviceid);
3506 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3508 qemu_devicedel
($vmid, $deviceid);
3509 qemu_devicedelverify
($vmid, $deviceid);
3510 qemu_drivedel
($vmid, $deviceid);
3511 qemu_iothread_del
($conf, $vmid, $deviceid);
3513 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3515 qemu_devicedel
($vmid, $deviceid);
3516 qemu_devicedelverify
($vmid, $deviceid);
3517 qemu_iothread_del
($conf, $vmid, $deviceid);
3519 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3521 #qemu 2.3 segfault on drive_del with virtioscsi + iothread
3522 my $device = parse_drive
($deviceid, $conf->{$deviceid});
3523 die "virtioscsi with iothread is not hot-unplugglable currently" if $device->{iothread
};
3525 qemu_devicedel
($vmid, $deviceid);
3526 qemu_drivedel
($vmid, $deviceid);
3527 qemu_deletescsihw
($conf, $vmid, $deviceid);
3529 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3531 qemu_devicedel
($vmid, $deviceid);
3532 qemu_devicedelverify
($vmid, $deviceid);
3533 qemu_netdevdel
($vmid, $deviceid);
3536 die "can't unplug device '$deviceid'\n";
3542 sub qemu_deviceadd
{
3543 my ($vmid, $devicefull) = @_;
3545 $devicefull = "driver=".$devicefull;
3546 my %options = split(/[=,]/, $devicefull);
3548 vm_mon_cmd
($vmid, "device_add" , %options);
3551 sub qemu_devicedel
{
3552 my ($vmid, $deviceid) = @_;
3554 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
3557 sub qemu_iothread_add
{
3558 my($vmid, $deviceid, $device) = @_;
3560 if ($device->{iothread
}) {
3561 my $iothreads = vm_iothreads_list
($vmid);
3562 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
3566 sub qemu_iothread_del
{
3567 my($conf, $vmid, $deviceid) = @_;
3569 my $device = parse_drive
($deviceid, $conf->{$deviceid});
3570 if ($device->{iothread
}) {
3571 my $iothreads = vm_iothreads_list
($vmid);
3572 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
3576 sub qemu_objectadd
{
3577 my($vmid, $objectid, $qomtype) = @_;
3579 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
3584 sub qemu_objectdel
{
3585 my($vmid, $objectid) = @_;
3587 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
3593 my ($storecfg, $vmid, $device) = @_;
3595 my $drive = print_drive_full
($storecfg, $vmid, $device);
3596 $drive =~ s/\\/\\\\/g;
3597 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
3599 # If the command succeeds qemu prints: "OK
"
3600 return 1 if $ret =~ m/OK/s;
3602 die "adding drive failed
: $ret\n";
3606 my($vmid, $deviceid) = @_;
3608 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
3611 return 1 if $ret eq "";
3613 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
3614 return 1 if $ret =~ m/Device \'.*?\' not found/s;
3616 die "deleting drive
$deviceid failed
: $ret\n";
3619 sub qemu_deviceaddverify {
3620 my ($vmid, $deviceid) = @_;
3622 for (my $i = 0; $i <= 5; $i++) {
3623 my $devices_list = vm_devices_list($vmid);
3624 return 1 if defined($devices_list->{$deviceid});
3628 die "error on hotplug device
'$deviceid'\n";
3632 sub qemu_devicedelverify {
3633 my ($vmid, $deviceid) = @_;
3635 # need to verify that the device is correctly removed as device_del
3636 # is async and empty return is not reliable
3638 for (my $i = 0; $i <= 5; $i++) {
3639 my $devices_list = vm_devices_list($vmid);
3640 return 1 if !defined($devices_list->{$deviceid});
3644 die "error on hot-unplugging device
'$deviceid'\n";
3647 sub qemu_findorcreatescsihw {
3648 my ($storecfg, $conf, $vmid, $device) = @_;
3650 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3652 my $scsihwid="$controller_prefix$controller";
3653 my $devices_list = vm_devices_list($vmid);
3655 if(!defined($devices_list->{$scsihwid})) {
3656 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device);
3662 sub qemu_deletescsihw {
3663 my ($conf, $vmid, $opt) = @_;
3665 my $device = parse_drive($opt, $conf->{$opt});
3667 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
3668 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
3672 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3674 my $devices_list = vm_devices_list($vmid);
3675 foreach my $opt (keys %{$devices_list}) {
3676 if (PVE::QemuServer::is_valid_drivename($opt)) {
3677 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
3678 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
3684 my $scsihwid="scsihw
$controller";
3686 vm_deviceunplug($vmid, $conf, $scsihwid);
3691 sub qemu_add_pci_bridge {
3692 my ($storecfg, $conf, $vmid, $device) = @_;
3698 print_pci_addr($device, $bridges);
3700 while (my ($k, $v) = each %$bridges) {
3703 return 1 if !defined($bridgeid) || $bridgeid < 1;
3705 my $bridge = "pci
.$bridgeid";
3706 my $devices_list = vm_devices_list($vmid);
3708 if (!defined($devices_list->{$bridge})) {
3709 vm_deviceplug($storecfg, $conf, $vmid, $bridge);
3715 sub qemu_set_link_status {
3716 my ($vmid, $device, $up) = @_;
3718 vm_mon_cmd($vmid, "set_link
", name => $device,
3719 up => $up ? JSON::true : JSON::false);
3722 sub qemu_netdevadd {
3723 my ($vmid, $conf, $device, $deviceid) = @_;
3725 my $netdev = print_netdev_full($vmid, $conf, $device, $deviceid, 1);
3726 my %options = split(/[=,]/, $netdev);
3728 vm_mon_cmd($vmid, "netdev_add
", %options);
3732 sub qemu_netdevdel {
3733 my ($vmid, $deviceid) = @_;
3735 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
3738 sub qemu_usb_hotplug {
3739 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
3743 # remove the old one first
3744 vm_deviceunplug($vmid, $conf, $deviceid);
3746 # check if xhci controller is necessary and available
3747 if ($device->{usb3}) {
3749 my $devicelist = vm_devices_list($vmid);
3751 if (!$devicelist->{xhci}) {
3752 my $pciaddr = print_pci_addr("xhci
");
3753 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
3756 my $d = parse_usb_device($device->{host});
3757 $d->{usb3} = $device->{usb3};
3760 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d);
3763 sub qemu_cpu_hotplug {
3764 my ($vmid, $conf, $vcpus) = @_;
3766 my $machine_type = PVE::QemuServer::get_current_qemu_machine($vmid);
3769 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
3770 $sockets = $conf->{sockets} if $conf->{sockets};
3771 my $cores = $conf->{cores} || 1;
3772 my $maxcpus = $sockets * $cores;
3774 $vcpus = $maxcpus if !$vcpus;
3776 die "you can
't add more vcpus than maxcpus\n"
3777 if $vcpus > $maxcpus;
3779 my $currentvcpus = $conf->{vcpus} || $maxcpus;
3781 if ($vcpus < $currentvcpus) {
3783 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
3785 for (my $i = $currentvcpus; $i > $vcpus; $i--) {
3786 qemu_devicedel($vmid, "cpu$i");
3788 my $currentrunningvcpus = undef;
3790 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
3791 last if scalar(@{$currentrunningvcpus}) == $i-1;
3792 raise_param_exc({ vcpus => "error unplugging cpu$i" }) if $retry > 5;
3796 #update conf after each succesfull cpu unplug
3797 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
3798 PVE::QemuConfig->write_config($vmid, $conf);
3801 die "cpu hot-unplugging requires qemu version 2.7 or higher\n";
3807 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
3808 die "vcpus in running vm does not match its configuration\n"
3809 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
3811 if (qemu_machine_feature_enabled ($machine_type, undef, 2, 7)) {
3813 for (my $i = $currentvcpus+1; $i <= $vcpus; $i++) {
3814 my $cpustr = print_cpu_device($conf, $i);
3815 qemu_deviceadd($vmid, $cpustr);
3818 my $currentrunningvcpus = undef;
3820 $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
3821 last if scalar(@{$currentrunningvcpus}) == $i;
3822 raise_param_exc({ vcpus => "error hotplugging cpu$i" }) if $retry > 10;
3826 #update conf after each succesfull cpu hotplug
3827 $conf->{vcpus} = scalar(@{$currentrunningvcpus});
3828 PVE::QemuConfig->write_config($vmid, $conf);
3832 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
3833 vm_mon_cmd($vmid, "cpu-add", id => int($i));
3838 sub qemu_block_set_io_throttle {
3839 my ($vmid, $deviceid,
3840 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
3841 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max,
3842 $bps_max_length, $bps_rd_max_length, $bps_wr_max_length,
3843 $iops_max_length, $iops_rd_max_length, $iops_wr_max_length) = @_;
3845 return if !check_running($vmid) ;
3847 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
3849 bps_rd => int($bps_rd),
3850 bps_wr => int($bps_wr),
3852 iops_rd => int($iops_rd),
3853 iops_wr => int($iops_wr),
3854 bps_max => int($bps_max),
3855 bps_rd_max => int($bps_rd_max),
3856 bps_wr_max => int($bps_wr_max),
3857 iops_max => int($iops_max),
3858 iops_rd_max => int($iops_rd_max),
3859 iops_wr_max => int($iops_wr_max),
3860 bps_max_length => int($bps_max_length),
3861 bps_rd_max_length => int($bps_rd_max_length),
3862 bps_wr_max_length => int($bps_wr_max_length),
3863 iops_max_length => int($iops_max_length),
3864 iops_rd_max_length => int($iops_rd_max_length),
3865 iops_wr_max_length => int($iops_wr_max_length),
3870 # old code, only used to shutdown old VM after update
3872 my ($fh, $timeout) = @_;
3874 my $sel = new IO::Select;
3881 while (scalar (@ready = $sel->can_read($timeout))) {
3883 if ($count = $fh->sysread($buf, 8192)) {
3884 if ($buf =~ /^(.*)\(qemu\) $/s) {
3891 if (!defined($count)) {
3898 die "monitor read timeout\n" if !scalar(@ready);
3903 # old code, only used to shutdown old VM after update
3904 sub vm_monitor_command {
3905 my ($vmid, $cmdstr, $nocheck) = @_;
3910 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
3912 my $sname = "${var_run_tmpdir}/$vmid.mon";
3914 my $sock = IO::Socket::UNIX->new( Peer => $sname ) ||
3915 die "unable to connect to VM $vmid socket - $!\n";
3919 # hack: migrate sometime blocks the monitor (when migrate_downtime
3921 if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
3922 $timeout = 60*60; # 1 hour
3926 my $data = __read_avail($sock, $timeout);
3928 if ($data !~ m/^QEMU\s+(\S+)\s+monitor\s/) {
3929 die "got unexpected qemu monitor banner\n";
3932 my $sel = new IO::Select;
3935 if (!scalar(my @ready = $sel->can_write($timeout))) {
3936 die "monitor write error - timeout";
3939 my $fullcmd = "$cmdstr\r";
3941 # syslog('info
', "VM $vmid monitor command: $cmdstr");
3944 if (!($b = $sock->syswrite($fullcmd)) || ($b != length($fullcmd))) {
3945 die "monitor write error - $!";
3948 return if ($cmdstr eq 'q
') || ($cmdstr eq 'quit
');
3952 if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
3953 $timeout = 60*60; # 1 hour
3954 } elsif ($cmdstr =~ m/^(eject|change)/) {
3955 $timeout = 60; # note: cdrom mount command is slow
3957 if ($res = __read_avail($sock, $timeout)) {
3959 my @lines = split("\r?\n", $res);
3961 shift @lines if $lines[0] !~ m/^unknown command/; # skip echo
3963 $res = join("\n", @lines);
3971 syslog("err", "VM $vmid monitor command failed - $err");
3978 sub qemu_block_resize {
3979 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
3981 my $running = check_running($vmid);
3983 return if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
3985 return if !$running;
3987 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
3991 sub qemu_volume_snapshot {
3992 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
3994 my $running = check_running($vmid);
3996 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
3997 vm_mon_cmd($vmid, "snapshot-drive", device => $deviceid, name => $snap);
3999 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
4003 sub qemu_volume_snapshot_delete {
4004 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
4006 my $running = check_running($vmid);
4008 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
4009 vm_mon_cmd($vmid, "delete-drive-snapshot", device => $deviceid, name => $snap);
4011 PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
4015 sub set_migration_caps {
4021 "auto-converge" => 1,
4023 "x-rdma-pin-all" => 0,
4028 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
4030 for my $supported_capability (@$supported_capabilities) {
4032 capability => $supported_capability->{capability},
4033 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4037 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
4040 my $fast_plug_option = {
4050 # hotplug changes in [PENDING]
4051 # $selection hash can be used to only apply specified options, for
4052 # example: { cores => 1 } (only apply changed 'cores
')
4053 # $errors ref is used to return error messages
4054 sub vmconfig_hotplug_pending {
4055 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4057 my $defaults = load_defaults();
4059 # commit values which do not have any impact on running VM first
4060 # Note: those option cannot raise errors, we we do not care about
4061 # $selection and always apply them.
4063 my $add_error = sub {
4064 my ($opt, $msg) = @_;
4065 $errors->{$opt} = "hotplug problem - $msg";
4069 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4070 if ($fast_plug_option->{$opt}) {
4071 $conf->{$opt} = $conf->{pending}->{$opt};
4072 delete $conf->{pending}->{$opt};
4078 PVE::QemuConfig->write_config($vmid, $conf);
4079 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4082 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4084 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4085 while (my ($opt, $force) = each %$pending_delete_hash) {
4086 next if $selection && !$selection->{$opt};
4088 if ($opt eq 'hotplug
') {
4089 die "skip\n" if ($conf->{hotplug} =~ /memory/);
4090 } elsif ($opt eq 'tablet
') {
4091 die "skip\n" if !$hotplug_features->{usb};
4092 if ($defaults->{tablet}) {
4093 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4095 vm_deviceunplug($vmid, $conf, $opt);
4097 } elsif ($opt =~ m/^usb\d+/) {
4099 # since we cannot reliably hot unplug usb devices
4100 # we are disabling it
4101 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
4102 vm_deviceunplug($vmid, $conf, $opt);
4103 } elsif ($opt eq 'vcpus
') {
4104 die "skip\n" if !$hotplug_features->{cpu};
4105 qemu_cpu_hotplug($vmid, $conf, undef);
4106 } elsif ($opt eq 'balloon
') {
4107 # enable balloon device is not hotpluggable
4108 die "skip\n" if !defined($conf->{balloon}) || $conf->{balloon};
4109 } elsif ($fast_plug_option->{$opt}) {
4111 } elsif ($opt =~ m/^net(\d+)$/) {
4112 die "skip\n" if !$hotplug_features->{network};
4113 vm_deviceunplug($vmid, $conf, $opt);
4114 } elsif (is_valid_drivename($opt)) {
4115 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4116 vm_deviceunplug($vmid, $conf, $opt);
4117 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4118 } elsif ($opt =~ m/^memory$/) {
4119 die "skip\n" if !$hotplug_features->{memory};
4120 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4121 } elsif ($opt eq 'cpuunits
') {
4122 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
4123 } elsif ($opt eq 'cpulimit
') {
4124 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
4130 &$add_error($opt, $err) if $err ne "skip\n";
4132 # save new config if hotplug was successful
4133 delete $conf->{$opt};
4134 vmconfig_undelete_pending_option($conf, $opt);
4135 PVE::QemuConfig->write_config($vmid, $conf);
4136 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4140 foreach my $opt (keys %{$conf->{pending}}) {
4141 next if $selection && !$selection->{$opt};
4142 my $value = $conf->{pending}->{$opt};
4144 if ($opt eq 'hotplug
') {
4145 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4146 } elsif ($opt eq 'tablet
') {
4147 die "skip\n" if !$hotplug_features->{usb};
4149 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4150 } elsif ($value == 0) {
4151 vm_deviceunplug($vmid, $conf, $opt);
4153 } elsif ($opt =~ m/^usb\d+$/) {
4155 # since we cannot reliably hot unplug usb devices
4156 # we are disabling it
4157 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
4158 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
4159 die "skip\n" if !$d;
4160 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d);
4161 } elsif ($opt eq 'vcpus
') {
4162 die "skip\n" if !$hotplug_features->{cpu};
4163 qemu_cpu_hotplug($vmid, $conf, $value);
4164 } elsif ($opt eq 'balloon
') {
4165 # enable/disable balloning device is not hotpluggable
4166 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4167 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4168 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
4170 # allow manual ballooning if shares is set to zero
4171 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4172 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4173 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4175 } elsif ($opt =~ m/^net(\d+)$/) {
4176 # some changes can be done without hotplug
4177 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4178 $vmid, $opt, $value);
4179 } elsif (is_valid_drivename($opt)) {
4180 # some changes can be done without hotplug
4181 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4182 $vmid, $opt, $value, 1);
4183 } elsif ($opt =~ m/^memory$/) { #dimms
4184 die "skip\n" if !$hotplug_features->{memory};
4185 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4186 } elsif ($opt eq 'cpuunits
') {
4187 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4188 } elsif ($opt eq 'cpulimit
') {
4189 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4190 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4192 die "skip\n"; # skip non-hot-pluggable options
4196 &$add_error($opt, $err) if $err ne "skip\n";
4198 # save new config if hotplug was successful
4199 $conf->{$opt} = $value;
4200 delete $conf->{pending}->{$opt};
4201 PVE::QemuConfig->write_config($vmid, $conf);
4202 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4207 sub try_deallocate_drive {
4208 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4210 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4211 my $volid = $drive->{file};
4212 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4213 my $sid = PVE::Storage::parse_volume_id($volid);
4214 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4216 # check if the disk is really unused
4217 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4218 if is_volume_in_use($storecfg, $conf, $key, $volid);
4219 PVE::Storage::vdisk_free($storecfg, $volid);
4222 # If vm is not owner of this disk remove from config
4230 sub vmconfig_delete_or_detach_drive {
4231 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4233 my $drive = parse_drive($opt, $conf->{$opt});
4235 my $rpcenv = PVE::RPCEnvironment::get();
4236 my $authuser = $rpcenv->get_user();
4239 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4240 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4242 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4246 sub vmconfig_apply_pending {
4247 my ($vmid, $conf, $storecfg) = @_;
4251 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4252 while (my ($opt, $force) = each %$pending_delete_hash) {
4253 die "internal error" if $opt =~ m/^unused/;
4254 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4255 if (!defined($conf->{$opt})) {
4256 vmconfig_undelete_pending_option($conf, $opt);
4257 PVE::QemuConfig->write_config($vmid, $conf);
4258 } elsif (is_valid_drivename($opt)) {
4259 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4260 vmconfig_undelete_pending_option($conf, $opt);
4261 delete $conf->{$opt};
4262 PVE::QemuConfig->write_config($vmid, $conf);
4264 vmconfig_undelete_pending_option($conf, $opt);
4265 delete $conf->{$opt};
4266 PVE::QemuConfig->write_config($vmid, $conf);
4270 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4272 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4273 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4275 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4276 # skip if nothing changed
4277 } elsif (is_valid_drivename($opt)) {
4278 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4279 if defined($conf->{$opt});
4280 $conf->{$opt} = $conf->{pending}->{$opt};
4282 $conf->{$opt} = $conf->{pending}->{$opt};
4285 delete $conf->{pending}->{$opt};
4286 PVE::QemuConfig->write_config($vmid, $conf);
4290 my $safe_num_ne = sub {
4293 return 0 if !defined($a) && !defined($b);
4294 return 1 if !defined($a);
4295 return 1 if !defined($b);
4300 my $safe_string_ne = sub {
4303 return 0 if !defined($a) && !defined($b);
4304 return 1 if !defined($a);
4305 return 1 if !defined($b);
4310 sub vmconfig_update_net {
4311 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value) = @_;
4313 my $newnet = parse_net($value);
4315 if ($conf->{$opt}) {
4316 my $oldnet = parse_net($conf->{$opt});
4318 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4319 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4320 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4321 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4323 # for non online change, we try to hot-unplug
4324 die "skip\n" if !$hotplug;
4325 vm_deviceunplug($vmid, $conf, $opt);
4328 die "internal error" if $opt !~ m/net(\d+)/;
4329 my $iface = "tap${vmid}i$1";
4331 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4332 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4333 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4334 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4335 PVE::Network::tap_unplug($iface);
4336 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4337 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4338 # Rate can be applied on its own but any change above needs to
4339 # include the rate in tap_plug since OVS resets everything.
4340 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4343 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4344 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4352 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet);
4358 sub vmconfig_update_disk {
4359 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force) = @_;
4361 # fixme: do we need force?
4363 my $drive = parse_drive($opt, $value);
4365 if ($conf->{$opt}) {
4367 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4369 my $media = $drive->{media} || 'disk
';
4370 my $oldmedia = $old_drive->{media} || 'disk
';
4371 die "unable to change media type\n" if $media ne $oldmedia;
4373 if (!drive_is_cdrom($old_drive)) {
4375 if ($drive->{file} ne $old_drive->{file}) {
4377 die "skip\n" if !$hotplug;
4379 # unplug and register as unused
4380 vm_deviceunplug($vmid, $conf, $opt);
4381 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4384 # update existing disk
4386 # skip non hotpluggable value
4387 if (&$safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
4388 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4389 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4390 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
4395 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4396 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4397 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4398 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4399 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4400 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4401 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4402 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4403 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4404 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4405 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4406 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
4407 &$safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
4408 &$safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
4409 &$safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
4410 &$safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
4411 &$safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
4412 &$safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
4414 qemu_block_set_io_throttle($vmid,"drive-$opt",
4415 ($drive->{mbps} || 0)*1024*1024,
4416 ($drive->{mbps_rd} || 0)*1024*1024,
4417 ($drive->{mbps_wr} || 0)*1024*1024,
4418 $drive->{iops} || 0,
4419 $drive->{iops_rd} || 0,
4420 $drive->{iops_wr} || 0,
4421 ($drive->{mbps_max} || 0)*1024*1024,
4422 ($drive->{mbps_rd_max} || 0)*1024*1024,
4423 ($drive->{mbps_wr_max} || 0)*1024*1024,
4424 $drive->{iops_max} || 0,
4425 $drive->{iops_rd_max} || 0,
4426 $drive->{iops_wr_max} || 0,
4427 $drive->{bps_max_length} || 1,
4428 $drive->{bps_rd_max_length} || 1,
4429 $drive->{bps_wr_max_length} || 1,
4430 $drive->{iops_max_length} || 1,
4431 $drive->{iops_rd_max_length} || 1,
4432 $drive->{iops_wr_max_length} || 1);
4441 if ($drive->{file} eq 'none
') {
4442 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
4444 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4445 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
4446 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
4454 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4456 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
4457 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive);
4461 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
4462 $forcemachine, $spice_ticket, $migration_network, $migration_type, $targetstorage) = @_;
4464 PVE::QemuConfig->lock_config($vmid, sub {
4465 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
4467 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
4469 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4471 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
4473 if (!$statefile && scalar(keys %{$conf->{pending}})) {
4474 vmconfig_apply_pending($vmid, $conf, $storecfg);
4475 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4478 my $defaults = load_defaults();
4480 # set environment variable useful inside network script
4481 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
4483 my $local_volumes = {};
4485 if ($targetstorage) {
4486 foreach_drive($conf, sub {
4487 my ($ds, $drive) = @_;
4489 return if drive_is_cdrom($drive);
4491 my $volid = $drive->{file};
4495 my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid);
4497 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4498 return if $scfg->{shared};
4499 $local_volumes->{$ds} = [$volid, $storeid, $volname];
4504 foreach my $opt (sort keys %$local_volumes) {
4506 my ($volid, $storeid, $volname) = @{$local_volumes->{$opt}};
4507 my $drive = parse_drive($opt, $conf->{$opt});
4509 #if remote storage is specified, use default format
4510 if ($targetstorage && $targetstorage ne "1") {
4511 $storeid = $targetstorage;
4512 my ($defFormat, $validFormats) = PVE::Storage::storage_default_format($storecfg, $storeid);
4513 $format = $defFormat;
4515 #else we use same format than original
4516 my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
4517 $format = qemu_img_format($scfg, $volid);
4520 my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
4521 my $newdrive = $drive;
4522 $newdrive->{format} = $format;
4523 $newdrive->{file} = $newvolid;
4524 my $drivestr = PVE::QemuServer::print_drive($vmid, $newdrive);
4525 $local_volumes->{$opt} = $drivestr;
4526 #pass drive to conf for command line
4527 $conf->{$opt} = $drivestr;
4531 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
4533 my $migrate_port = 0;
4536 if ($statefile eq 'tcp
') {
4537 my $localip = "localhost";
4538 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
4539 my $nodename = PVE::INotify::nodename();
4541 if (!defined($migration_type)) {
4542 if (defined($datacenterconf->{migration}->{type})) {
4543 $migration_type = $datacenterconf->{migration}->{type};
4545 $migration_type = 'secure
';
4549 if ($migration_type eq 'insecure
') {
4550 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
4551 if ($migrate_network_addr) {
4552 $localip = $migrate_network_addr;
4554 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
4557 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4560 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4561 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4562 $migrate_uri = "tcp:${localip}:${migrate_port}";
4563 push @$cmd, '-incoming
', $migrate_uri;
4566 } elsif ($statefile eq 'unix
') {
4567 # should be default for secure migrations as a ssh TCP forward
4568 # tunnel is not deterministic reliable ready and fails regurarly
4569 # to set up in time, so use UNIX socket forwards
4570 my $socket_addr = "/run/qemu-server/$vmid.migrate";
4571 unlink $socket_addr;
4573 $migrate_uri = "unix:$socket_addr";
4575 push @$cmd, '-incoming
', $migrate_uri;
4579 push @$cmd, '-loadstate
', $statefile;
4586 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
4587 my $d = parse_hostpci($conf->{"hostpci$i"});
4589 my $pcidevices = $d->{pciid};
4590 foreach my $pcidevice (@$pcidevices) {
4591 my $pciid = $pcidevice->{id}.".".$pcidevice->{function};
4593 my $info = pci_device_info("0000:$pciid");
4594 die "IOMMU not present\n" if !check_iommu_support();
4595 die "no pci device info for device '$pciid'\n" if !$info;
4596 die "can't unbind
/bind pci group to vfio
'$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
4597 die "can
't reset pci device '$pciid'\n" if $info->{has_fl_reset} and !pci_dev_reset($info);
4601 PVE::Storage::activate_volumes($storecfg, $vollist);
4603 if (!check_running($vmid, 1) && -d "/sys/fs/cgroup/systemd/qemu.slice/$vmid.scope") {
4605 push @$cmd, '/bin/systemctl
', 'stop
', "$vmid.scope";
4606 eval { run_command($cmd); };
4609 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
4610 : $defaults->{cpuunits};
4612 my %run_params = (timeout => $statefile ? undef : 30, umask => 0077);
4615 Slice => 'qemu
.slice
',
4617 CPUShares => $cpuunits
4620 if (my $cpulimit = $conf->{cpulimit}) {
4621 $properties{CPUQuota} = int($cpulimit * 100);
4623 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
4625 if ($conf->{hugepages}) {
4628 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
4629 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
4631 PVE::QemuServer::Memory::hugepages_mount();
4632 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
4635 PVE::Tools::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4636 run_command($cmd, %run_params);
4640 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
4644 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
4646 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
4650 PVE::Tools::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4651 run_command($cmd, %run_params);
4656 # deactivate volumes if start fails
4657 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
4658 die "start failed: $err";
4661 print "migration listens on $migrate_uri\n" if $migrate_uri;
4663 if ($statefile && $statefile ne 'tcp
') {
4664 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
4668 #start nbd server for storage migration
4669 if ($targetstorage) {
4670 my $nodename = PVE::INotify::nodename();
4671 my $migrate_network_addr = PVE::Cluster::get_local_migration_ip($migration_network);
4672 my $localip = $migrate_network_addr ? $migrate_network_addr : PVE::Cluster::remote_node_ip($nodename, 1);
4673 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4674 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4676 vm_mon_cmd_nocheck($vmid, "nbd-server-start", addr => { type => 'inet
', data => { host => "${localip}", port => "${migrate_port}" } } );
4678 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4680 foreach my $opt (sort keys %$local_volumes) {
4681 my $volid = $local_volumes->{$opt};
4682 vm_mon_cmd_nocheck($vmid, "nbd-server-add", device => "drive-$opt", writable => JSON::true );
4683 my $migrate_storage_uri = "nbd:${localip}:${migrate_port}:exportname=drive-$opt";
4684 print "storage migration listens on $migrate_storage_uri volume:$volid\n";
4688 if ($migratedfrom) {
4690 set_migration_caps($vmid);
4695 print "spice listens on port $spice_port\n";
4696 if ($spice_ticket) {
4697 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
4698 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
4703 if (!$statefile && (!defined($conf->{balloon}) || $conf->{balloon})) {
4704 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
4705 if $conf->{balloon};
4708 foreach my $opt (keys %$conf) {
4709 next if $opt !~ m/^net\d+$/;
4710 my $nicconf = parse_net($conf->{$opt});
4711 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
4715 vm_mon_cmd_nocheck($vmid, 'qom-set
',
4716 path => "machine/peripheral/balloon0",
4717 property => "guest-stats-polling-interval",
4718 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
4724 my ($vmid, $execute, %params) = @_;
4726 my $cmd = { execute => $execute, arguments => \%params };
4727 vm_qmp_command($vmid, $cmd);
4730 sub vm_mon_cmd_nocheck {
4731 my ($vmid, $execute, %params) = @_;
4733 my $cmd = { execute => $execute, arguments => \%params };
4734 vm_qmp_command($vmid, $cmd, 1);
4737 sub vm_qmp_command {
4738 my ($vmid, $cmd, $nocheck) = @_;
4743 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
4744 $timeout = $cmd->{arguments}->{timeout};
4745 delete $cmd->{arguments}->{timeout};
4749 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
4750 my $sname = qmp_socket($vmid);
4751 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
4752 my $qmpclient = PVE::QMPClient->new();
4754 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
4755 } elsif (-e "${var_run_tmpdir}/$vmid.mon") {
4756 die "can't execute complex command on old monitor
- stop
/start your vm to fix the problem
\n"
4757 if scalar(%{$cmd->{arguments}});
4758 vm_monitor_command($vmid, $cmd->{execute}, $nocheck);
4760 die "unable to
open monitor
socket\n";
4764 syslog("err
", "VM
$vmid qmp command failed
- $err");
4771 sub vm_human_monitor_command {
4772 my ($vmid, $cmdline) = @_;
4777 execute => 'human-monitor-command',
4778 arguments => { 'command-line' => $cmdline},
4781 return vm_qmp_command($vmid, $cmd);
4784 sub vm_commandline {
4785 my ($storecfg, $vmid) = @_;
4787 my $conf = PVE::QemuConfig->load_config($vmid);
4789 my $defaults = load_defaults();
4791 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
4793 return PVE::Tools::cmd2string($cmd);
4797 my ($vmid, $skiplock) = @_;
4799 PVE::QemuConfig->lock_config($vmid, sub {
4801 my $conf = PVE::QemuConfig->load_config($vmid);
4803 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4805 vm_mon_cmd($vmid, "system_reset
");
4809 sub get_vm_volumes {
4813 foreach_volid($conf, sub {
4814 my ($volid, $is_cdrom) = @_;
4816 return if $volid =~ m|^/|;
4818 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
4821 push @$vollist, $volid;
4827 sub vm_stop_cleanup {
4828 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
4833 my $vollist = get_vm_volumes($conf);
4834 PVE::Storage::deactivate_volumes($storecfg, $vollist);
4837 foreach my $ext (qw(mon qmp pid vnc qga)) {
4838 unlink "/var/run/qemu-server/${vmid}.$ext";
4841 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
4843 warn $@ if $@; # avoid errors - just warn
4846 # Note: use $nockeck to skip tests if VM configuration file exists.
4847 # We need that when migration VMs to other nodes (files already moved)
4848 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
4850 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
4852 $force = 1 if !defined($force) && !$shutdown;
4855 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
4856 kill 15, $pid if $pid;
4857 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
4858 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
4862 PVE
::QemuConfig-
>lock_config($vmid, sub {
4864 my $pid = check_running
($vmid, $nocheck);
4869 $conf = PVE
::QemuConfig-
>load_config($vmid);
4870 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
4871 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
4872 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
4873 $timeout = $opts->{down
} if $opts->{down
};
4877 $timeout = 60 if !defined($timeout);
4881 if (defined($conf) && $conf->{agent
}) {
4882 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
4884 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
4887 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
4894 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
4899 if ($count >= $timeout) {
4901 warn "VM still running - terminating now with SIGTERM\n";
4904 die "VM quit/powerdown failed - got timeout\n";
4907 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
4912 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
4915 die "VM quit/powerdown failed\n";
4923 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
4928 if ($count >= $timeout) {
4929 warn "VM still running - terminating now with SIGKILL\n";
4934 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
4939 my ($vmid, $skiplock) = @_;
4941 PVE
::QemuConfig-
>lock_config($vmid, sub {
4943 my $conf = PVE
::QemuConfig-
>load_config($vmid);
4945 PVE
::QemuConfig-
>check_lock($conf)
4946 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
4948 vm_mon_cmd
($vmid, "stop");
4953 my ($vmid, $skiplock, $nocheck) = @_;
4955 PVE
::QemuConfig-
>lock_config($vmid, sub {
4959 my $conf = PVE
::QemuConfig-
>load_config($vmid);
4961 PVE
::QemuConfig-
>check_lock($conf)
4962 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
4964 vm_mon_cmd
($vmid, "cont");
4967 vm_mon_cmd_nocheck
($vmid, "cont");
4973 my ($vmid, $skiplock, $key) = @_;
4975 PVE
::QemuConfig-
>lock_config($vmid, sub {
4977 my $conf = PVE
::QemuConfig-
>load_config($vmid);
4979 # there is no qmp command, so we use the human monitor command
4980 vm_human_monitor_command
($vmid, "sendkey $key");
4985 my ($storecfg, $vmid, $skiplock) = @_;
4987 PVE
::QemuConfig-
>lock_config($vmid, sub {
4989 my $conf = PVE
::QemuConfig-
>load_config($vmid);
4991 if (!check_running
($vmid)) {
4992 destroy_vm
($storecfg, $vmid, undef, $skiplock);
4994 die "VM $vmid is running - destroy failed\n";
5002 my ($filename, $buf) = @_;
5004 my $fh = IO
::File-
>new($filename, "w");
5005 return undef if !$fh;
5007 my $res = print $fh $buf;
5014 sub pci_device_info
{
5019 return undef if $name !~ m/^([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\.([a-f0-9])$/;
5020 my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4);
5022 my $irq = file_read_firstline
("$pcisysfs/devices/$name/irq");
5023 return undef if !defined($irq) || $irq !~ m/^\d+$/;
5025 my $vendor = file_read_firstline
("$pcisysfs/devices/$name/vendor");
5026 return undef if !defined($vendor) || $vendor !~ s/^0x//;
5028 my $product = file_read_firstline
("$pcisysfs/devices/$name/device");
5029 return undef if !defined($product) || $product !~ s/^0x//;
5034 product
=> $product,
5040 has_fl_reset
=> -f
"$pcisysfs/devices/$name/reset" || 0,
5049 my $name = $dev->{name
};
5051 my $fn = "$pcisysfs/devices/$name/reset";
5053 return file_write
($fn, "1");
5056 sub pci_dev_bind_to_vfio
{
5059 my $name = $dev->{name
};
5061 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5063 if (!-d
$vfio_basedir) {
5064 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5066 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5068 my $testdir = "$vfio_basedir/$name";
5069 return 1 if -d
$testdir;
5071 my $data = "$dev->{vendor} $dev->{product}";
5072 return undef if !file_write
("$vfio_basedir/new_id", $data);
5074 my $fn = "$pcisysfs/devices/$name/driver/unbind";
5075 if (!file_write
($fn, $name)) {
5076 return undef if -f
$fn;
5079 $fn = "$vfio_basedir/bind";
5080 if (! -d
$testdir) {
5081 return undef if !file_write
($fn, $name);
5087 sub pci_dev_group_bind_to_vfio
{
5090 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
5092 if (!-d
$vfio_basedir) {
5093 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
5095 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
5097 # get IOMMU group devices
5098 opendir(my $D, "$pcisysfs/devices/0000:$pciid/iommu_group/devices/") || die "Cannot open iommu_group: $!\n";
5099 my @devs = grep /^0000:/, readdir($D);
5102 foreach my $pciid (@devs) {
5103 $pciid =~ m/^([:\.\da-f]+)$/ or die "PCI ID $pciid not valid!\n";
5105 # pci bridges, switches or root ports are not supported
5106 # they have a pci_bus subdirectory so skip them
5107 next if (-e
"$pcisysfs/devices/$pciid/pci_bus");
5109 my $info = pci_device_info
($1);
5110 pci_dev_bind_to_vfio
($info) || die "Cannot bind $pciid to vfio\n";
5116 # vzdump restore implementaion
5118 sub tar_archive_read_firstfile
{
5119 my $archive = shift;
5121 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5123 # try to detect archive type first
5124 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
5125 die "unable to open file '$archive'\n";
5126 my $firstfile = <$fh>;
5130 die "ERROR: archive contaions no data\n" if !$firstfile;
5136 sub tar_restore_cleanup
{
5137 my ($storecfg, $statfile) = @_;
5139 print STDERR
"starting cleanup\n";
5141 if (my $fd = IO
::File-
>new($statfile, "r")) {
5142 while (defined(my $line = <$fd>)) {
5143 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5146 if ($volid =~ m
|^/|) {
5147 unlink $volid || die 'unlink failed\n';
5149 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5151 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5153 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5155 print STDERR
"unable to parse line in statfile - $line";
5162 sub restore_archive
{
5163 my ($archive, $vmid, $user, $opts) = @_;
5165 my $format = $opts->{format
};
5168 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5169 $format = 'tar' if !$format;
5171 } elsif ($archive =~ m/\.tar$/) {
5172 $format = 'tar' if !$format;
5173 } elsif ($archive =~ m/.tar.lzo$/) {
5174 $format = 'tar' if !$format;
5176 } elsif ($archive =~ m/\.vma$/) {
5177 $format = 'vma' if !$format;
5178 } elsif ($archive =~ m/\.vma\.gz$/) {
5179 $format = 'vma' if !$format;
5181 } elsif ($archive =~ m/\.vma\.lzo$/) {
5182 $format = 'vma' if !$format;
5185 $format = 'vma' if !$format; # default
5188 # try to detect archive format
5189 if ($format eq 'tar') {
5190 return restore_tar_archive
($archive, $vmid, $user, $opts);
5192 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5196 sub restore_update_config_line
{
5197 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5199 return if $line =~ m/^\#qmdump\#/;
5200 return if $line =~ m/^\#vzdump\#/;
5201 return if $line =~ m/^lock:/;
5202 return if $line =~ m/^unused\d+:/;
5203 return if $line =~ m/^parent:/;
5204 return if $line =~ m/^template:/; # restored VM is never a template
5206 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
5207 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5208 # try to convert old 1.X settings
5209 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5210 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5211 my ($model, $macaddr) = split(/\=/, $devconfig);
5212 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
5215 bridge
=> "vmbr$ind",
5216 macaddr
=> $macaddr,
5218 my $netstr = print_net
($net);
5220 print $outfd "net$cookie->{netcount}: $netstr\n";
5221 $cookie->{netcount
}++;
5223 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5224 my ($id, $netstr) = ($1, $2);
5225 my $net = parse_net
($netstr);
5226 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
5227 $netstr = print_net
($net);
5228 print $outfd "$id: $netstr\n";
5229 } elsif ($line =~ m/^((ide|scsi|virtio|sata|efidisk)\d+):\s*(\S+)\s*$/) {
5232 my $di = parse_drive
($virtdev, $value);
5233 if (defined($di->{backup
}) && !$di->{backup
}) {
5234 print $outfd "#$line";
5235 } elsif ($map->{$virtdev}) {
5236 delete $di->{format
}; # format can change on restore
5237 $di->{file
} = $map->{$virtdev};
5238 $value = print_drive
($vmid, $di);
5239 print $outfd "$virtdev: $value\n";
5249 my ($cfg, $vmid) = @_;
5251 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5253 my $volid_hash = {};
5254 foreach my $storeid (keys %$info) {
5255 foreach my $item (@{$info->{$storeid}}) {
5256 next if !($item->{volid
} && $item->{size
});
5257 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5258 $volid_hash->{$item->{volid
}} = $item;
5265 sub is_volume_in_use
{
5266 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5268 my $path = PVE
::Storage
::path
($storecfg, $volid);
5270 my $scan_config = sub {
5271 my ($cref, $snapname) = @_;
5273 foreach my $key (keys %$cref) {
5274 my $value = $cref->{$key};
5275 if (is_valid_drivename
($key)) {
5276 next if $skip_drive && $key eq $skip_drive;
5277 my $drive = parse_drive
($key, $value);
5278 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5279 return 1 if $volid eq $drive->{file
};
5280 if ($drive->{file
} =~ m!^/!) {
5281 return 1 if $drive->{file
} eq $path;
5283 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5285 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5287 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5295 return 1 if &$scan_config($conf);
5299 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5300 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5306 sub update_disksize
{
5307 my ($vmid, $conf, $volid_hash) = @_;
5313 # Note: it is allowed to define multiple storages with same path (alias), so
5314 # we need to check both 'volid' and real 'path' (two different volid can point
5315 # to the same path).
5320 foreach my $opt (keys %$conf) {
5321 if (is_valid_drivename
($opt)) {
5322 my $drive = parse_drive
($opt, $conf->{$opt});
5323 my $volid = $drive->{file
};
5326 $used->{$volid} = 1;
5327 if ($volid_hash->{$volid} &&
5328 (my $path = $volid_hash->{$volid}->{path
})) {
5329 $usedpath->{$path} = 1;
5332 next if drive_is_cdrom
($drive);
5333 next if !$volid_hash->{$volid};
5335 $drive->{size
} = $volid_hash->{$volid}->{size
};
5336 my $new = print_drive
($vmid, $drive);
5337 if ($new ne $conf->{$opt}) {
5339 $conf->{$opt} = $new;
5344 # remove 'unusedX' entry if volume is used
5345 foreach my $opt (keys %$conf) {
5346 next if $opt !~ m/^unused\d+$/;
5347 my $volid = $conf->{$opt};
5348 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5349 if ($used->{$volid} || ($path && $usedpath->{$path})) {
5351 delete $conf->{$opt};
5355 foreach my $volid (sort keys %$volid_hash) {
5356 next if $volid =~ m/vm-$vmid-state-/;
5357 next if $used->{$volid};
5358 my $path = $volid_hash->{$volid}->{path
};
5359 next if !$path; # just to be sure
5360 next if $usedpath->{$path};
5362 PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5363 $usedpath->{$path} = 1; # avoid to add more than once (aliases)
5370 my ($vmid, $nolock) = @_;
5372 my $cfg = PVE
::Storage
::config
();
5374 my $volid_hash = scan_volids
($cfg, $vmid);
5376 my $updatefn = sub {
5379 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5381 PVE
::QemuConfig-
>check_lock($conf);
5384 foreach my $volid (keys %$volid_hash) {
5385 my $info = $volid_hash->{$volid};
5386 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5389 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5391 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes;
5394 if (defined($vmid)) {
5398 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5401 my $vmlist = config_list
();
5402 foreach my $vmid (keys %$vmlist) {
5406 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5412 sub restore_vma_archive
{
5413 my ($archive, $vmid, $user, $opts, $comp) = @_;
5415 my $input = $archive eq '-' ?
"<&STDIN" : undef;
5416 my $readfrom = $archive;
5421 my $qarchive = PVE
::Tools
::shellquote
($archive);
5422 if ($comp eq 'gzip') {
5423 $uncomp = "zcat $qarchive|";
5424 } elsif ($comp eq 'lzop') {
5425 $uncomp = "lzop -d -c $qarchive|";
5427 die "unknown compression method '$comp'\n";
5432 my $tmpdir = "/var/tmp/vzdumptmp$$";
5435 # disable interrupts (always do cleanups)
5436 local $SIG{INT
} = $SIG{TERM
} = $SIG{QUIT
} = $SIG{HUP
} = sub {
5437 warn "got interrupt - ignored\n";
5440 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
5441 POSIX
::mkfifo
($mapfifo, 0600);
5444 my $openfifo = sub {
5445 open($fifofh, '>', $mapfifo) || die $!;
5448 my $cmd = "${uncomp}vma extract -v -r $mapfifo $readfrom $tmpdir";
5455 my $rpcenv = PVE
::RPCEnvironment
::get
();
5457 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5458 my $tmpfn = "$conffile.$$.tmp";
5460 # Note: $oldconf is undef if VM does not exists
5461 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
5462 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
5464 my $print_devmap = sub {
5465 my $virtdev_hash = {};
5467 my $cfgfn = "$tmpdir/qemu-server.conf";
5469 # we can read the config - that is already extracted
5470 my $fh = IO
::File-
>new($cfgfn, "r") ||
5471 "unable to read qemu-server.conf - $!\n";
5473 my $fwcfgfn = "$tmpdir/qemu-server.fw";
5475 my $pve_firewall_dir = '/etc/pve/firewall';
5476 mkdir $pve_firewall_dir; # make sure the dir exists
5477 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
5480 while (defined(my $line = <$fh>)) {
5481 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
5482 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
5483 die "archive does not contain data for drive '$virtdev'\n"
5484 if !$devinfo->{$devname};
5485 if (defined($opts->{storage
})) {
5486 $storeid = $opts->{storage
} || 'local';
5487 } elsif (!$storeid) {
5490 $format = 'raw' if !$format;
5491 $devinfo->{$devname}->{devname
} = $devname;
5492 $devinfo->{$devname}->{virtdev
} = $virtdev;
5493 $devinfo->{$devname}->{format
} = $format;
5494 $devinfo->{$devname}->{storeid
} = $storeid;
5496 # check permission on storage
5497 my $pool = $opts->{pool
}; # todo: do we need that?
5498 if ($user ne 'root@pam') {
5499 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
5502 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
5506 foreach my $devname (keys %$devinfo) {
5507 die "found no device mapping information for device '$devname'\n"
5508 if !$devinfo->{$devname}->{virtdev
};
5511 my $cfg = PVE
::Storage
::config
();
5513 # create empty/temp config
5515 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
5516 foreach_drive
($oldconf, sub {
5517 my ($ds, $drive) = @_;
5519 return if drive_is_cdrom
($drive);
5521 my $volid = $drive->{file
};
5523 return if !$volid || $volid =~ m
|^/|;
5525 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
5526 return if !$path || !$owner || ($owner != $vmid);
5528 # Note: only delete disk we want to restore
5529 # other volumes will become unused
5530 if ($virtdev_hash->{$ds}) {
5531 eval { PVE
::Storage
::vdisk_free
($cfg, $volid); };
5538 # delete vmstate files
5539 # since after the restore we have no snapshots anymore
5540 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
5541 my $snap = $oldconf->{snapshots
}->{$snapname};
5542 if ($snap->{vmstate
}) {
5543 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
5552 foreach my $virtdev (sort keys %$virtdev_hash) {
5553 my $d = $virtdev_hash->{$virtdev};
5554 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
5555 my $scfg = PVE
::Storage
::storage_config
($cfg, $d->{storeid
});
5557 # test if requested format is supported
5558 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $d->{storeid
});
5559 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
5560 $d->{format
} = $defFormat if !$supported;
5562 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $d->{storeid
}, $vmid,
5563 $d->{format
}, undef, $alloc_size);
5564 print STDERR
"new volume ID is '$volid'\n";
5565 $d->{volid
} = $volid;
5566 my $path = PVE
::Storage
::path
($cfg, $volid);
5568 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
5570 my $write_zeros = 1;
5571 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
5575 print $fifofh "format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
5577 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
5578 $map->{$virtdev} = $volid;
5581 $fh->seek(0, 0) || die "seek failed - $!\n";
5583 my $outfd = new IO
::File
($tmpfn, "w") ||
5584 die "unable to write config for VM $vmid\n";
5586 my $cookie = { netcount
=> 0 };
5587 while (defined(my $line = <$fh>)) {
5588 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
5597 local $SIG{INT
} = $SIG{TERM
} = $SIG{QUIT
} = $SIG{HUP
} = $SIG{PIPE
} = sub {
5598 die "interrupted by signal\n";
5600 local $SIG{ALRM
} = sub { die "got timeout\n"; };
5602 $oldtimeout = alarm($timeout);
5609 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
5610 my ($dev_id, $size, $devname) = ($1, $2, $3);
5611 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
5612 } elsif ($line =~ m/^CTIME: /) {
5613 # we correctly received the vma config, so we can disable
5614 # the timeout now for disk allocation (set to 10 minutes, so
5615 # that we always timeout if something goes wrong)
5618 print $fifofh "done\n";
5619 my $tmp = $oldtimeout || 0;
5620 $oldtimeout = undef;
5626 print "restore vma archive: $cmd\n";
5627 run_command
($cmd, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
5631 alarm($oldtimeout) if $oldtimeout;
5634 foreach my $devname (keys %$devinfo) {
5635 my $volid = $devinfo->{$devname}->{volid
};
5636 push @$vollist, $volid if $volid;
5639 my $cfg = PVE
::Storage
::config
();
5640 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
5648 foreach my $devname (keys %$devinfo) {
5649 my $volid = $devinfo->{$devname}->{volid
};
5652 if ($volid =~ m
|^/|) {
5653 unlink $volid || die 'unlink failed\n';
5655 PVE
::Storage
::vdisk_free
($cfg, $volid);
5657 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5659 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5666 rename($tmpfn, $conffile) ||
5667 die "unable to commit configuration file '$conffile'\n";
5669 PVE
::Cluster
::cfs_update
(); # make sure we read new file
5671 eval { rescan
($vmid, 1); };
5675 sub restore_tar_archive
{
5676 my ($archive, $vmid, $user, $opts) = @_;
5678 if ($archive ne '-') {
5679 my $firstfile = tar_archive_read_firstfile
($archive);
5680 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
5681 if $firstfile ne 'qemu-server.conf';
5684 my $storecfg = PVE
::Storage
::config
();
5686 # destroy existing data - keep empty config
5687 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
5688 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
5690 my $tocmd = "/usr/lib/qemu-server/qmextract";
5692 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
5693 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
5694 $tocmd .= ' --prealloc' if $opts->{prealloc
};
5695 $tocmd .= ' --info' if $opts->{info
};
5697 # tar option "xf" does not autodetect compression when read from STDIN,
5698 # so we pipe to zcat
5699 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
5700 PVE
::Tools
::shellquote
("--to-command=$tocmd");
5702 my $tmpdir = "/var/tmp/vzdumptmp$$";
5705 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
5706 local $ENV{VZDUMP_VMID
} = $vmid;
5707 local $ENV{VZDUMP_USER
} = $user;
5709 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5710 my $tmpfn = "$conffile.$$.tmp";
5712 # disable interrupts (always do cleanups)
5713 local $SIG{INT
} = $SIG{TERM
} = $SIG{QUIT
} = $SIG{HUP
} = sub {
5714 print STDERR
"got interrupt - ignored\n";
5719 local $SIG{INT
} = $SIG{TERM
} = $SIG{QUIT
} = $SIG{HUP
} = $SIG{PIPE
} = sub {
5720 die "interrupted by signal\n";
5723 if ($archive eq '-') {
5724 print "extracting archive from STDIN\n";
5725 run_command
($cmd, input
=> "<&STDIN");
5727 print "extracting archive '$archive'\n";
5731 return if $opts->{info
};
5735 my $statfile = "$tmpdir/qmrestore.stat";
5736 if (my $fd = IO
::File-
>new($statfile, "r")) {
5737 while (defined (my $line = <$fd>)) {
5738 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5739 $map->{$1} = $2 if $1;
5741 print STDERR
"unable to parse line in statfile - $line\n";
5747 my $confsrc = "$tmpdir/qemu-server.conf";
5749 my $srcfd = new IO
::File
($confsrc, "r") ||
5750 die "unable to open file '$confsrc'\n";
5752 my $outfd = new IO
::File
($tmpfn, "w") ||
5753 die "unable to write config for VM $vmid\n";
5755 my $cookie = { netcount
=> 0 };
5756 while (defined (my $line = <$srcfd>)) {
5757 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
5769 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
5776 rename $tmpfn, $conffile ||
5777 die "unable to commit configuration file '$conffile'\n";
5779 PVE
::Cluster
::cfs_update
(); # make sure we read new file
5781 eval { rescan
($vmid, 1); };
5785 sub foreach_writable_storage
{
5786 my ($conf, $func) = @_;
5790 foreach my $ds (keys %$conf) {
5791 next if !is_valid_drivename
($ds);
5793 my $drive = parse_drive
($ds, $conf->{$ds});
5795 next if drive_is_cdrom
($drive);
5797 my $volid = $drive->{file
};
5799 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
5800 $sidhash->{$sid} = $sid if $sid;
5803 foreach my $sid (sort keys %$sidhash) {
5808 sub do_snapshots_with_qemu
{
5809 my ($storecfg, $volid) = @_;
5811 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
5813 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
5814 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
5818 if ($volid =~ m/\.(qcow2|qed)$/){
5825 sub qga_check_running
{
5828 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
5830 warn "Qemu Guest Agent are not running - $@";
5836 sub template_create
{
5837 my ($vmid, $conf, $disk) = @_;
5839 my $storecfg = PVE
::Storage
::config
();
5841 foreach_drive
($conf, sub {
5842 my ($ds, $drive) = @_;
5844 return if drive_is_cdrom
($drive);
5845 return if $disk && $ds ne $disk;
5847 my $volid = $drive->{file
};
5848 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
5850 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
5851 $drive->{file
} = $voliddst;
5852 $conf->{$ds} = print_drive
($vmid, $drive);
5853 PVE
::QemuConfig-
>write_config($vmid, $conf);
5857 sub qemu_img_convert
{
5858 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
5860 my $storecfg = PVE
::Storage
::config
();
5861 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
5862 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
5864 if ($src_storeid && $dst_storeid) {
5866 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
5868 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
5869 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
5871 my $src_format = qemu_img_format
($src_scfg, $src_volname);
5872 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
5874 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
5875 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
5878 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
5879 push @$cmd, '-s', $snapname if($snapname && $src_format eq "qcow2");
5880 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
5881 if ($is_zero_initialized) {
5882 push @$cmd, "zeroinit:$dst_path";
5884 push @$cmd, $dst_path;
5889 if($line =~ m/\((\S+)\/100\
%\)/){
5891 my $transferred = int($size * $percent / 100);
5892 my $remaining = $size - $transferred;
5894 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
5899 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
5901 die "copy failed: $err" if $err;
5905 sub qemu_img_format
{
5906 my ($scfg, $volname) = @_;
5908 if ($scfg->{path
} && $volname =~ m/\.(raw|cow|qcow|qcow2|qed|vmdk|cloop)$/) {
5915 sub qemu_drive_mirror
{
5916 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized, $jobs, $skipcomplete, $qga) = @_;
5918 $jobs = {} if !$jobs;
5922 $jobs->{"drive-$drive"} = {};
5924 if ($dst_volid =~ /^nbd:(localhost|[\d\.]+|\[[\d\.:a-fA-F]+\]):(\d+):exportname=(\S+)/) {
5927 my $exportname = $3;
5930 my $unixsocket = "/run/qemu-server/$vmid.mirror-drive-$drive";
5931 $qemu_target = "nbd+unix:///$exportname?socket=$unixsocket";
5932 my $cmd = ['socat', '-T30', "UNIX-LISTEN:$unixsocket,fork", "TCP:$server:$2,connect-timeout=5"];
5935 if (!defined($pid)) {
5936 die "forking socat tunnel failed\n";
5937 } elsif ($pid == 0) {
5939 warn "exec failed: $!\n";
5942 $jobs->{"drive-$drive"}->{pid
} = $pid;
5945 while (!-S
$unixsocket) {
5946 die "nbd connection helper timed out\n"
5951 my $storecfg = PVE
::Storage
::config
();
5952 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
5954 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
5956 $format = qemu_img_format
($dst_scfg, $dst_volname);
5958 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
5960 $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
5963 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
5964 $opts->{format
} = $format if $format;
5966 print "drive mirror is starting for drive-$drive\n";
5968 eval { vm_mon_cmd
($vmid, "drive-mirror", %$opts); }; #if a job already run for this device,it's throw an error
5971 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
5972 die "mirroring error: $err";
5975 qemu_drive_mirror_monitor
($vmid, $vmiddst, $jobs, $skipcomplete, $qga);
5978 sub qemu_drive_mirror_monitor
{
5979 my ($vmid, $vmiddst, $jobs, $skipcomplete, $qga) = @_;
5982 my $err_complete = 0;
5985 die "storage migration timed out\n" if $err_complete > 300;
5987 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
5989 my $running_mirror_jobs = {};
5990 foreach my $stat (@$stats) {
5991 next if $stat->{type
} ne 'mirror';
5992 $running_mirror_jobs->{$stat->{device
}} = $stat;
5995 my $readycounter = 0;
5997 foreach my $job (keys %$jobs) {
5999 if(defined($jobs->{$job}->{complete
}) && !defined($running_mirror_jobs->{$job})) {
6000 print "$job : finished\n";
6001 delete $jobs->{$job};
6005 die "$job: mirroring has been cancelled\n" if !defined($running_mirror_jobs->{$job});
6007 my $busy = $running_mirror_jobs->{$job}->{busy
};
6008 my $ready = $running_mirror_jobs->{$job}->{ready
};
6009 if (my $total = $running_mirror_jobs->{$job}->{len
}) {
6010 my $transferred = $running_mirror_jobs->{$job}->{offset
} || 0;
6011 my $remaining = $total - $transferred;
6012 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
6014 print "$job: transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
6017 $readycounter++ if $running_mirror_jobs->{$job}->{ready
} eq 'true';
6020 last if scalar(keys %$jobs) == 0;
6022 if ($readycounter == scalar(keys %$jobs)) {
6023 print "all mirroring jobs are ready \n";
6024 last if $skipcomplete; #do the complete later
6026 if ($vmiddst && $vmiddst != $vmid) {
6028 print "freeze filesystem\n";
6029 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-freeze"); };
6031 print "suspend vm\n";
6032 eval { PVE
::QemuServer
::vm_suspend
($vmid, 1); };
6035 # if we clone a disk for a new target vm, we don't switch the disk
6036 PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs);
6039 print "unfreeze filesystem\n";
6040 eval { PVE
::QemuServer
::vm_mon_cmd
($vmid, "guest-fsfreeze-thaw"); };
6042 print "resume vm\n";
6043 eval { PVE
::QemuServer
::vm_resume
($vmid, 1, 1); };
6049 foreach my $job (keys %$jobs) {
6050 # try to switch the disk if source and destination are on the same guest
6051 print "$job: Completing block job...\n";
6053 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> $job) };
6054 if ($@ =~ m/cannot be completed/) {
6055 print "$job: Block job cannot be completed, try again.\n";
6058 print "$job: Completed successfully.\n";
6059 $jobs->{$job}->{complete
} = 1;
6060 eval { qemu_blockjobs_finish_tunnel
($vmid, $job, $jobs->{$job}->{pid
}) } ;
6071 eval { PVE
::QemuServer
::qemu_blockjobs_cancel
($vmid, $jobs) };
6072 die "mirroring error: $err";
6077 sub qemu_blockjobs_cancel
{
6078 my ($vmid, $jobs) = @_;
6080 foreach my $job (keys %$jobs) {
6081 print "$job: Cancelling block job\n";
6082 eval { vm_mon_cmd
($vmid, "block-job-cancel", device
=> $job); };
6083 $jobs->{$job}->{cancel
} = 1;
6087 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
6089 my $running_jobs = {};
6090 foreach my $stat (@$stats) {
6091 $running_jobs->{$stat->{device
}} = $stat;
6094 foreach my $job (keys %$jobs) {
6096 if (defined($jobs->{$job}->{cancel
}) && !defined($running_jobs->{$job})) {
6097 print "$job: Done.\n";
6098 eval { qemu_blockjobs_finish_tunnel
($vmid, $job, $jobs->{$job}->{pid
}) } ;
6099 delete $jobs->{$job};
6103 last if scalar(keys %$jobs) == 0;
6109 sub qemu_blockjobs_finish_tunnel
{
6110 my ($vmid, $job, $cpid) = @_;
6114 for (my $i = 1; $i < 20; $i++) {
6115 my $waitpid = waitpid($cpid, WNOHANG
);
6116 last if (defined($waitpid) && ($waitpid == $cpid));
6120 } elsif ($i >= 15) {
6125 unlink "/run/qemu-server/$vmid.mirror-$job";
6129 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
6130 $newvmid, $storage, $format, $full, $newvollist, $jobs, $skipcomplete, $qga) = @_;
6135 print "create linked clone of drive $drivename ($drive->{file})\n";
6136 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
6137 push @$newvollist, $newvolid;
6140 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
6141 $storeid = $storage if $storage;
6143 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
6145 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
6146 $format = qemu_img_format
($scfg, $volname);
6149 # test if requested format is supported - else use default
6150 my $supported = grep { $_ eq $format } @$validFormats;
6151 $format = $defFormat if !$supported;
6153 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
6155 print "create full clone of drive $drivename ($drive->{file})\n";
6156 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $format, undef, ($size/1024));
6157 push @$newvollist, $newvolid;
6159 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
6161 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
6162 if (!$running || $snapname) {
6163 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
6166 my $kvmver = get_running_qemu_version
($vmid);
6167 if (!qemu_machine_feature_enabled
(undef, $kvmver, 2, 7)) {
6168 die "drive-mirror with iothread requires qemu version 2.7 or higher\n"
6169 if $drive->{iothread
};
6172 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $skipcomplete, $qga);
6176 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
6179 $disk->{format
} = undef;
6180 $disk->{file
} = $newvolid;
6181 $disk->{size
} = $size;
6186 # this only works if VM is running
6187 sub get_current_qemu_machine
{
6190 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
6191 my $res = vm_qmp_command
($vmid, $cmd);
6193 my ($current, $default);
6194 foreach my $e (@$res) {
6195 $default = $e->{name
} if $e->{'is-default'};
6196 $current = $e->{name
} if $e->{'is-current'};
6199 # fallback to the default machine if current is not supported by qemu
6200 return $current || $default || 'pc';
6203 sub get_running_qemu_version
{
6205 my $cmd = { execute
=> 'query-version', arguments
=> {} };
6206 my $res = vm_qmp_command
($vmid, $cmd);
6207 return "$res->{qemu}->{major}.$res->{qemu}->{minor}";
6210 sub qemu_machine_feature_enabled
{
6211 my ($machine, $kvmver, $version_major, $version_minor) = @_;
6216 if ($machine && $machine =~ m/^(pc(-i440fx|-q35)?-(\d+)\.(\d+))/) {
6218 $current_major = $3;
6219 $current_minor = $4;
6221 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6223 $current_major = $1;
6224 $current_minor = $2;
6227 return 1 if $current_major >= $version_major && $current_minor >= $version_minor;
6232 sub qemu_machine_pxe
{
6233 my ($vmid, $conf, $machine) = @_;
6235 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6237 foreach my $opt (keys %$conf) {
6238 next if $opt !~ m/^net(\d+)$/;
6239 my $net = PVE
::QemuServer
::parse_net
($conf->{$opt});
6241 my $romfile = PVE
::QemuServer
::vm_mon_cmd_nocheck
($vmid, 'qom-get', path
=> $opt, property
=> 'romfile');
6242 return $machine.".pxe" if $romfile =~ m/pxe/;
6249 sub qemu_use_old_bios_files
{
6250 my ($machine_type) = @_;
6252 return if !$machine_type;
6254 my $use_old_bios_files = undef;
6256 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6258 $use_old_bios_files = 1;
6260 my $kvmver = kvm_user_version
();
6261 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6262 # load new efi bios files on migration. So this hack is required to allow
6263 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6264 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6265 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6268 return ($use_old_bios_files, $machine_type);
6275 dir_glob_foreach
("$pcisysfs/devices", '[a-f0-9]{4}:([a-f0-9]{2}:[a-f0-9]{2})\.([0-9])', sub {
6276 my (undef, $id, $function) = @_;
6277 my $res = { id
=> $id, function
=> $function};
6278 push @{$devices->{$id}}, $res;
6284 sub vm_iothreads_list
{
6287 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6290 foreach my $iothread (@$res) {
6291 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6298 my ($conf, $drive) = @_;
6302 if ($conf->{scsihw
} && ($conf->{scsihw
} =~ m/^lsi/)) {
6304 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6310 my $controller = int($drive->{index} / $maxdev);
6311 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6313 return ($maxdev, $controller, $controller_prefix);
6316 sub add_hyperv_enlighments
{
6317 my ($cpuFlags, $winversion, $machine_type, $kvmver, $nokvm, $bios, $gpu_passthrough) = @_;
6320 return if $winversion < 6;
6321 return if $bios && $bios eq 'ovmf' && $winversion < 8;
6323 push @$cpuFlags , 'hv_vendor_id=proxmox' if $gpu_passthrough;
6325 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
6326 push @$cpuFlags , 'hv_spinlocks=0x1fff';
6327 push @$cpuFlags , 'hv_vapic';
6328 push @$cpuFlags , 'hv_time';
6330 push @$cpuFlags , 'hv_spinlocks=0xffff';
6333 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
6334 push @$cpuFlags , 'hv_reset';
6335 push @$cpuFlags , 'hv_vpindex';
6336 push @$cpuFlags , 'hv_runtime';
6339 if ($winversion >= 7) {
6340 push @$cpuFlags , 'hv_relaxed';
6344 sub windows_version
{
6347 return 0 if !$ostype;
6351 if($ostype eq 'wxp' || $ostype eq 'w2k3' || $ostype eq 'w2k') {
6353 } elsif($ostype eq 'w2k8' || $ostype eq 'wvista') {
6355 } elsif ($ostype =~ m/^win(\d+)$/) {
6362 # bash completion helper
6364 sub complete_backup_archives
{
6365 my ($cmdname, $pname, $cvalue) = @_;
6367 my $cfg = PVE
::Storage
::config
();
6371 if ($cvalue =~ m/^([^:]+):/) {
6375 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
6378 foreach my $id (keys %$data) {
6379 foreach my $item (@{$data->{$id}}) {
6380 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
6381 push @$res, $item->{volid
} if defined($item->{volid
});
6388 my $complete_vmid_full = sub {
6391 my $idlist = vmstatus
();
6395 foreach my $id (keys %$idlist) {
6396 my $d = $idlist->{$id};
6397 if (defined($running)) {
6398 next if $d->{template
};
6399 next if $running && $d->{status
} ne 'running';
6400 next if !$running && $d->{status
} eq 'running';
6409 return &$complete_vmid_full();
6412 sub complete_vmid_stopped
{
6413 return &$complete_vmid_full(0);
6416 sub complete_vmid_running
{
6417 return &$complete_vmid_full(1);
6420 sub complete_storage
{
6422 my $cfg = PVE
::Storage
::config
();
6423 my $ids = $cfg->{ids
};
6426 foreach my $sid (keys %$ids) {
6427 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
6428 next if !$ids->{$sid}->{content
}->{images
};
6438 vm_mon_cmd
($vmid, 'nbd-server-stop');