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 $qemu_snap_storage = {rbd
=> 1, sheepdog
=> 1};
42 my $cpuinfo = PVE
::ProcFSTools
::read_cpuinfo
();
44 # Note about locking: we use flock on the config file protect
45 # against concurent actions.
46 # Aditionaly, we have a 'lock' setting in the config file. This
47 # can be set to 'migrate', 'backup', 'snapshot' or 'rollback'. Most actions are not
48 # allowed when such lock is set. But you can ignore this kind of
49 # lock with the --skiplock flag.
51 cfs_register_file
('/qemu-server/',
55 PVE
::JSONSchema
::register_standard_option
('skiplock', {
56 description
=> "Ignore locks - only root is allowed to use this option.",
61 PVE
::JSONSchema
::register_standard_option
('pve-qm-stateuri', {
62 description
=> "Some command save/restore state from this location.",
68 PVE
::JSONSchema
::register_standard_option
('pve-snapshot-name', {
69 description
=> "The name of the snapshot.",
70 type
=> 'string', format
=> 'pve-configid',
74 #no warnings 'redefine';
77 my ($controller, $vmid, $option, $value) = @_;
79 my $path = "/sys/fs/cgroup/$controller/qemu.slice/$vmid.scope/$option";
80 PVE
::ProcFSTools
::write_proc_entry
($path, $value);
84 my $nodename = PVE
::INotify
::nodename
();
86 mkdir "/etc/pve/nodes/$nodename";
87 my $confdir = "/etc/pve/nodes/$nodename/qemu-server";
90 my $var_run_tmpdir = "/var/run/qemu-server";
91 mkdir $var_run_tmpdir;
93 my $lock_dir = "/var/lock/qemu-server";
96 my $pcisysfs = "/sys/bus/pci";
98 my $cpu_vendor_list = {
100 486 => 'GenuineIntel',
101 pentium
=> 'GenuineIntel',
102 pentium2
=> 'GenuineIntel',
103 pentium3
=> 'GenuineIntel',
104 coreduo
=> 'GenuineIntel',
105 core2duo
=> 'GenuineIntel',
106 Conroe
=> 'GenuineIntel',
107 Penryn
=> 'GenuineIntel',
108 Nehalem
=> 'GenuineIntel',
109 Westmere
=> 'GenuineIntel',
110 SandyBridge
=> 'GenuineIntel',
111 IvyBridge
=> 'GenuineIntel',
112 Haswell
=> 'GenuineIntel',
113 'Haswell-noTSX' => 'GenuineIntel',
114 Broadwell
=> 'GenuineIntel',
115 'Broadwell-noTSX' => 'GenuineIntel',
118 athlon
=> 'AuthenticAMD',
119 phenom
=> 'AuthenticAMD',
120 Opteron_G1
=> 'AuthenticAMD',
121 Opteron_G2
=> 'AuthenticAMD',
122 Opteron_G3
=> 'AuthenticAMD',
123 Opteron_G4
=> 'AuthenticAMD',
124 Opteron_G5
=> 'AuthenticAMD',
126 # generic types, use vendor from host node
136 description
=> "Emulated CPU type.",
138 enum
=> [ sort { "\L$a" cmp "\L$b" } keys %$cpu_vendor_list ],
139 format_description
=> 'cputype',
144 description
=> "Do not identify as a KVM virtual machine.",
155 enum
=> [qw(i6300esb ib700)],
156 description
=> "Watchdog type to emulate.",
157 default => 'i6300esb',
162 enum
=> [qw(reset shutdown poweroff pause debug none)],
163 description
=> "The action to perform if after activation the guest fails to poll the watchdog in time.",
167 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', $watchdog_fmt);
173 description
=> "Specifies whether a VM will be started during system bootup.",
179 description
=> "Automatic restart after crash (currently ignored).",
184 type
=> 'string', format
=> 'pve-hotplug-features',
185 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'.",
186 default => 'network,disk,usb',
191 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
197 description
=> "Lock/unlock the VM.",
198 enum
=> [qw(migrate backup snapshot rollback)],
203 description
=> "Limit of CPU usage.",
204 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.",
212 description
=> "CPU weight for a VM.",
213 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.",
221 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
228 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
234 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",
242 description
=> "Keybord layout for vnc server. Default is read from the '/etc/pve/datacenter.conf' configuration file.",
243 enum
=> PVE
::Tools
::kvmkeymaplist
(),
248 type
=> 'string', format
=> 'dns-name',
249 description
=> "Set a name for the VM. Only used on the configuration web interface.",
254 description
=> "SCSI controller model",
255 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
261 description
=> "Description for the VM. Only used on the configuration web interface. This is saved as comment inside the configuration file.",
266 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 l24 l26 solaris)],
267 description
=> "Specify guest operating system.",
268 verbose_description
=> <<EODESC,
269 Specify guest operating system. This is used to enable special
270 optimization/features for specific operating systems:
273 other;; unspecified OS
274 wxp;; Microsoft Windows XP
275 w2k;; Microsoft Windows 2000
276 w2k3;; Microsoft Windows 2003
277 w2k8;; Microsoft Windows 2008
278 wvista;; Microsoft Windows Vista
279 win7;; Microsoft Windows 7
280 win8;; Microsoft Windows 8/2012
281 l24;; Linux 2.4 Kernel
282 l26;; Linux 2.6/3.X Kernel
283 solaris;; Solaris/OpenSolaris/OpenIndiania kernel
289 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
290 pattern
=> '[acdn]{1,4}',
295 type
=> 'string', format
=> 'pve-qm-bootdisk',
296 description
=> "Enable booting from specified disk.",
297 pattern
=> '(ide|sata|scsi|virtio)\d+',
302 description
=> "The number of CPUs. Please use option -sockets instead.",
309 description
=> "The number of CPU sockets.",
316 description
=> "The number of cores per socket.",
323 description
=> "Enable/disable NUMA.",
329 description
=> "Enable/disable hugepages memory.",
330 enum
=> [qw(any 2 1024)],
335 description
=> "Number of hotplugged vcpus.",
342 description
=> "Enable/disable ACPI.",
348 description
=> "Enable/disable Qemu GuestAgent.",
354 description
=> "Enable/disable KVM hardware virtualization.",
360 description
=> "Enable/disable time drift fix.",
366 description
=> "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
371 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
376 description
=> "Select the VGA type.",
377 verbose_description
=> "Select the VGA type. If you want to use high resolution" .
378 " modes (>= 1280x1024x16) then you should use the options " .
379 "'std' or 'vmware'. Default is 'std' for win8/win7/w2k8, and " .
380 "'cirrus' for other OS types. The 'qxl' option enables the SPICE " .
381 "display sever. For win* OS you can select how many independent " .
382 "displays you want, Linux guests can add displays them self. " .
383 "You can also run without any graphic card, using a serial device" .
385 enum
=> [qw(std cirrus vmware qxl serial0 serial1 serial2 serial3 qxl2 qxl3 qxl4)],
389 type
=> 'string', format
=> 'pve-qm-watchdog',
390 description
=> "Create a virtual hardware watchdog device.",
391 verbose_description
=> "Create a virtual hardware watchdog device. Once enabled" .
392 " (by a guest action), the watchdog must be periodically polled " .
393 "by an agent inside the guest or else the watchdog will reset " .
394 "the guest (or execute the respective action specified)",
399 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
400 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'.",
401 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
404 startup
=> get_standard_option
('pve-startup-order'),
408 description
=> "Enable/disable Template.",
414 description
=> "Arbitrary arguments passed to kvm.",
415 verbose_description
=> <<EODESCR,
416 Arbitrary arguments passed to kvm, for example:
418 args: -no-reboot -no-hpet
420 NOTE: this option is for experts only.
427 description
=> "Enable/disable the USB tablet device.",
428 verbose_description
=> "Enable/disable the USB tablet device. This device is " .
429 "usually needed to allow absolute mouse positioning with VNC. " .
430 "Else the mouse runs out of sync with normal VNC clients. " .
431 "If you're running lots of console-only guests on one host, " .
432 "you may consider disabling this to save some context switches. " .
433 "This is turned off by default if you use spice (-vga=qxl).",
438 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
442 migrate_downtime
=> {
445 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
451 type
=> 'string', format
=> 'pve-qm-drive',
452 typetext
=> 'volume',
453 description
=> "This is an alias for option -ide2",
457 description
=> "Emulated CPU type.",
461 parent
=> get_standard_option
('pve-snapshot-name', {
463 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
467 description
=> "Timestamp for snapshots.",
473 type
=> 'string', format
=> 'pve-volume-id',
474 description
=> "Reference to a volume which stores the VM state. This is used internally for snapshots.",
477 description
=> "Specific the Qemu machine type.",
479 pattern
=> '(pc|pc(-i440fx)?-\d+\.\d+(\.pxe)?|q35|pc-q35-\d+\.\d+(\.pxe)?)',
484 description
=> "Specify SMBIOS type 1 fields.",
485 type
=> 'string', format
=> 'pve-qm-smbios1',
492 description
=> "Sets the protection flag of the VM. This will disable the remove VM and remove disk operations.",
498 enum
=> [ qw(seabios ovmf) ],
499 description
=> "Select BIOS implementation.",
500 default => 'seabios',
504 # what about other qemu settings ?
506 #machine => 'string',
519 ##soundhw => 'string',
521 while (my ($k, $v) = each %$confdesc) {
522 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
525 my $MAX_IDE_DISKS = 4;
526 my $MAX_SCSI_DISKS = 14;
527 my $MAX_VIRTIO_DISKS = 16;
528 my $MAX_SATA_DISKS = 6;
529 my $MAX_USB_DEVICES = 5;
531 my $MAX_UNUSED_DISKS = 8;
532 my $MAX_HOSTPCI_DEVICES = 4;
533 my $MAX_SERIAL_PORTS = 4;
534 my $MAX_PARALLEL_PORTS = 3;
540 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
541 description
=> "CPUs accessing this NUMA node.",
542 format_description
=> "id[-id];...",
546 description
=> "Amount of memory this NUMA node provides.",
551 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
552 description
=> "Host NUMA nodes to use.",
553 format_description
=> "id[-id];...",
558 enum
=> [qw(preferred bind interleave)],
559 description
=> "NUMA allocation policy.",
563 PVE
::JSONSchema
::register_format
('pve-qm-numanode', $numa_fmt);
566 type
=> 'string', format
=> $numa_fmt,
567 description
=> "NUMA topology.",
569 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
571 for (my $i = 0; $i < $MAX_NUMA; $i++) {
572 $confdesc->{"numa$i"} = $numadesc;
575 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
576 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
577 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
578 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
580 my $net_fmt_bridge_descr = <<__EOD__;
581 Bridge to attach the network device to. The Proxmox VE standard bridge
584 If you do not specify a bridge, we create a kvm user (NATed) network
585 device, which provides DHCP and DNS services. The following addresses
592 The DHCP server assign addresses to the guest starting from 10.0.2.15.
598 pattern
=> qr/[0-9a-f]{2}(?::[0-9a-f]{2}){5}/i,
599 description
=> "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
600 format_description
=> "XX:XX:XX:XX:XX:XX",
605 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'.",
606 format_description
=> 'model',
607 enum
=> $nic_model_list,
610 (map { $_ => { keyAlias
=> 'model', alias
=> 'macaddr' }} @$nic_model_list),
613 description
=> $net_fmt_bridge_descr,
614 format_description
=> 'bridge',
619 minimum
=> 0, maximum
=> 16,
620 description
=> 'Number of packet queues to be used on the device.',
626 description
=> "Rate limit in mbps (megabytes per second) as floating point number.",
631 minimum
=> 1, maximum
=> 4094,
632 description
=> 'VLAN tag to apply to packets on this interface.',
637 pattern
=> qr/\d+(?:-\d+)?(?:;\d+(?:-\d+)?)*/,
638 description
=> 'VLAN trunks to pass through this interface.',
639 format_description
=> 'vlanid[;vlanid...]',
644 description
=> 'Whether this interface should be protected by the firewall.',
649 description
=> 'Whether this interface should be disconnected (like pulling the plug).',
656 type
=> 'string', format
=> $net_fmt,
657 description
=> "Specify network devices.",
660 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
662 for (my $i = 0; $i < $MAX_NETS; $i++) {
663 $confdesc->{"net$i"} = $netdesc;
666 PVE
::JSONSchema
::register_format
('pve-volume-id-or-qm-path', \
&verify_volume_id_or_qm_path
);
667 sub verify_volume_id_or_qm_path
{
668 my ($volid, $noerr) = @_;
670 if ($volid eq 'none' || $volid eq 'cdrom' || $volid =~ m
|^/|) {
674 # if its neither 'none' nor 'cdrom' nor a path, check if its a volume-id
675 $volid = eval { PVE
::JSONSchema
::check_format
('pve-volume-id', $volid, '') };
677 return undef if $noerr;
685 my %drivedesc_base = (
686 volume
=> { alias
=> 'file' },
689 format
=> 'pve-volume-id-or-qm-path',
691 format_description
=> 'volume',
692 description
=> "The drive's backing volume.",
696 enum
=> [qw(cdrom disk)],
697 description
=> "The drive's media type.",
703 description
=> "Force the drive's physical geometry to have a specific cylinder count.",
708 description
=> "Force the drive's physical geometry to have a specific head count.",
713 description
=> "Force the drive's physical geometry to have a specific sector count.",
718 enum
=> [qw(none lba auto)],
719 description
=> "Force disk geometry bios translation mode.",
724 description
=> "Whether the drive should be included when making snapshots.",
729 enum
=> [qw(none writethrough writeback unsafe directsync)],
730 description
=> "The drive's cache mode",
735 format_description
=> 'image format',
736 enum
=> [qw(raw cow qcow qed qcow2 vmdk cloop)],
737 description
=> "The drive's backing file's data format.",
742 format
=> 'disk-size',
743 format_description
=> 'DiskSize',
744 description
=> "Disk size. This is purely informational and has no effect.",
749 description
=> "Whether the drive should be included when making backups.",
754 enum
=> [qw(enospc ignore report stop)],
755 description
=> 'Write error action.',
760 enum
=> [qw(native threads)],
761 description
=> 'AIO type to use.',
766 enum
=> [qw(ignore on)],
767 description
=> 'Controls whether to pass discard/trim requests to the underlying storage.',
772 description
=> 'Controls whether to detect and try to optimize writes of zeroes.',
777 format
=> 'urlencoded',
778 format_description
=> 'serial',
779 maxLength
=> 20*3, # *3 since it's %xx url enoded
780 description
=> "The drive's reported serial number, url-encoded, up to 20 bytes long.",
788 enum
=> [qw(ignore report stop)],
789 description
=> 'Read error action.',
794 my %iothread_fmt = ( iothread
=> {
796 description
=> "Whether to use iothreads for this drive",
803 format
=> 'urlencoded',
804 format_description
=> 'model',
805 maxLength
=> 40*3, # *3 since it's %xx url enoded
806 description
=> "The drive's reported model name, url-encoded, up to 40 bytes long.",
814 description
=> "Number of queues.",
820 my $add_throttle_desc = sub {
821 my ($key, $type, $what, $unit, $longunit) = @_;
822 $drivedesc_base{$key} = {
824 format_description
=> $unit,
825 description
=> "Maximum $what speed in $longunit per second.",
829 # throughput: (leaky bucket)
830 $add_throttle_desc->('bps', 'integer', 'r/w speed', 'bps', 'bytes');
831 $add_throttle_desc->('bps_rd', 'integer', 'read speed', 'bps', 'bytes');
832 $add_throttle_desc->('bps_wr', 'integer', 'write speed', 'bps', 'bytes');
833 $add_throttle_desc->('mbps', 'number', 'r/w speed', 'mbps', 'megabytes');
834 $add_throttle_desc->('mbps_rd', 'number', 'read speed', 'mbps', 'megabytes');
835 $add_throttle_desc->('mbps_wr', 'number', 'write speed', 'mbps', 'megabytes');
836 $add_throttle_desc->('iops', 'integer', 'r/w I/O', 'iops', 'operations');
837 $add_throttle_desc->('iops_rd', 'integer', 'read I/O', 'iops', 'operations');
838 $add_throttle_desc->('iops_wr', 'integer', 'write I/O', 'iops', 'operations');
840 # pools: (pool of IO before throttling starts taking effect)
841 $add_throttle_desc->('mbps_max', 'number', 'unthrottled r/w pool', 'mbps', 'megabytes');
842 $add_throttle_desc->('mbps_rd_max', 'number', 'unthrottled read pool', 'mbps', 'megabytes');
843 $add_throttle_desc->('mbps_wr_max', 'number', 'unthrottled write pool', 'mbps', 'megabytes');
844 $add_throttle_desc->('iops_max', 'integer', 'unthrottled r/w I/O pool', 'iops', 'operations');
845 $add_throttle_desc->('iops_rd_max', 'integer', 'unthrottled read I/O pool', 'iops', 'operations');
846 $add_throttle_desc->('iops_wr_max', 'integer', 'unthrottled write I/O pool', 'iops', 'operations');
856 type
=> 'string', format
=> $ide_fmt,
857 description
=> "Use volume as IDE hard disk or CD-ROM (n is 0 to " .($MAX_IDE_DISKS -1) . ").",
859 PVE
::JSONSchema
::register_standard_option
("pve-qm-ide", $idedesc);
868 type
=> 'string', format
=> $scsi_fmt,
869 description
=> "Use volume as SCSI hard disk or CD-ROM (n is 0 to " . ($MAX_SCSI_DISKS - 1) . ").",
871 PVE
::JSONSchema
::register_standard_option
("pve-qm-scsi", $scsidesc);
879 type
=> 'string', format
=> $sata_fmt,
880 description
=> "Use volume as SATA hard disk or CD-ROM (n is 0 to " . ($MAX_SATA_DISKS - 1). ").",
882 PVE
::JSONSchema
::register_standard_option
("pve-qm-sata", $satadesc);
891 type
=> 'string', format
=> $virtio_fmt,
892 description
=> "Use volume as VIRTIO hard disk (n is 0 to " . ($MAX_VIRTIO_DISKS - 1) . ").",
894 PVE
::JSONSchema
::register_standard_option
("pve-qm-virtio", $virtiodesc);
907 type
=> 'string', format
=> 'pve-qm-usb-device',
908 format_description
=> 'HOSTUSBDEVICE|spice',
909 description
=> <<EODESCR,
910 The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
912 'bus-port(.port)*' (decimal numbers) or
913 'vendor_id:product_id' (hexadeciaml numbers) or
916 You can use the 'lsusb -t' command to list existing usb devices.
918 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
920 The value 'spice' can be used to add a usb redirection devices for spice.
926 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).",
933 type
=> 'string', format
=> $usb_fmt,
934 description
=> "Configure an USB device (n is 0 to 4).",
936 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
938 # NOTE: the match-groups of this regex are used in parse_hostpci
939 my $PCIRE = qr/([a-f0-9]{2}:[a-f0-9]{2})(?:\.([a-f0-9]))?/;
944 pattern
=> qr/$PCIRE(;$PCIRE)*/,
945 format_description
=> 'HOSTPCIID[;HOSTPCIID2...]',
946 description
=> <<EODESCR,
947 Host PCI device pass through. The PCI ID of a host's PCI device or a list
948 of PCI virtual functions of the host. HOSTPCIID syntax is:
950 'bus:dev.func' (hexadecimal numbers)
952 You can us the 'lspci' command to list existing PCI devices.
957 description
=> "Specify whether or not the device's ROM will be visible in the guest's memory map.",
963 description
=> "Choose the PCI-express bus (needs the 'q35' machine model).",
969 description
=> "Enable vfio-vga device support.",
974 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', $hostpci_fmt);
978 type
=> 'string', format
=> 'pve-qm-hostpci',
979 description
=> "Map host PCI devices into guest.",
980 verbose_description
=> <<EODESCR,
981 Map host PCI devices into guest.
983 NOTE: This option allows direct access to host hardware. So it is no longer
984 possible to migrate such machines - use with special care.
986 CAUTION: Experimental! User reported problems with this option.
989 PVE
::JSONSchema
::register_standard_option
("pve-qm-hostpci", $hostpcidesc);
994 pattern
=> '(/dev/.+|socket)',
995 description
=> "Create a serial device inside the VM (n is 0 to 3)",
996 verbose_description
=> <<EODESCR,
997 Create a serial device inside the VM (n is 0 to 3), and pass through a
998 host serial device (i.e. /dev/ttyS0), or create a unix socket on the
999 host side (use 'qm terminal' to open a terminal connection).
1001 NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
1003 CAUTION: Experimental! User reported problems with this option.
1010 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
1011 description
=> "Map host parallel devices (n is 0 to 2).",
1012 verbose_description
=> <<EODESCR,
1013 Map host parallel devices (n is 0 to 2).
1015 NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
1017 CAUTION: Experimental! User reported problems with this option.
1021 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
1022 $confdesc->{"parallel$i"} = $paralleldesc;
1025 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
1026 $confdesc->{"serial$i"} = $serialdesc;
1029 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
1030 $confdesc->{"hostpci$i"} = $hostpcidesc;
1033 for (my $i = 0; $i < $MAX_IDE_DISKS; $i++) {
1034 $drivename_hash->{"ide$i"} = 1;
1035 $confdesc->{"ide$i"} = $idedesc;
1038 for (my $i = 0; $i < $MAX_SATA_DISKS; $i++) {
1039 $drivename_hash->{"sata$i"} = 1;
1040 $confdesc->{"sata$i"} = $satadesc;
1043 for (my $i = 0; $i < $MAX_SCSI_DISKS; $i++) {
1044 $drivename_hash->{"scsi$i"} = 1;
1045 $confdesc->{"scsi$i"} = $scsidesc ;
1048 for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++) {
1049 $drivename_hash->{"virtio$i"} = 1;
1050 $confdesc->{"virtio$i"} = $virtiodesc;
1053 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
1054 $confdesc->{"usb$i"} = $usbdesc;
1059 type
=> 'string', format
=> 'pve-volume-id',
1060 description
=> "Reference to unused volumes. This is used internally, and should not be modified manually.",
1063 for (my $i = 0; $i < $MAX_UNUSED_DISKS; $i++) {
1064 $confdesc->{"unused$i"} = $unuseddesc;
1067 my $kvm_api_version = 0;
1071 return $kvm_api_version if $kvm_api_version;
1073 my $fh = IO
::File-
>new("</dev/kvm") ||
1076 if (my $v = $fh->ioctl(KVM_GET_API_VERSION
(), 0)) {
1077 $kvm_api_version = $v;
1082 return $kvm_api_version;
1085 my $kvm_user_version;
1087 sub kvm_user_version
{
1089 return $kvm_user_version if $kvm_user_version;
1091 $kvm_user_version = 'unknown';
1095 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
1096 $kvm_user_version = $2;
1100 eval { run_command
("kvm -version", outfunc
=> $code); };
1103 return $kvm_user_version;
1107 my $kernel_has_vhost_net = -c
'/dev/vhost-net';
1109 sub valid_drive_names
{
1110 # order is important - used to autoselect boot disk
1111 return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
1112 (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
1113 (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))),
1114 (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))));
1117 sub is_valid_drivename
{
1120 return defined($drivename_hash->{$dev});
1125 return defined($confdesc->{$key});
1129 return $nic_model_list;
1132 sub os_list_description
{
1136 wxp
=> 'Windows XP',
1137 w2k
=> 'Windows 2000',
1138 w2k3
=>, 'Windows 2003',
1139 w2k8
=> 'Windows 2008',
1140 wvista
=> 'Windows Vista',
1141 win7
=> 'Windows 7',
1142 win8
=> 'Windows 8/2012',
1150 sub get_cdrom_path
{
1152 return $cdrom_path if $cdrom_path;
1154 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
1155 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
1156 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
1160 my ($storecfg, $vmid, $cdrom) = @_;
1162 if ($cdrom eq 'cdrom') {
1163 return get_cdrom_path
();
1164 } elsif ($cdrom eq 'none') {
1166 } elsif ($cdrom =~ m
|^/|) {
1169 return PVE
::Storage
::path
($storecfg, $cdrom);
1173 # try to convert old style file names to volume IDs
1174 sub filename_to_volume_id
{
1175 my ($vmid, $file, $media) = @_;
1177 if (!($file eq 'none' || $file eq 'cdrom' ||
1178 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
1180 return undef if $file =~ m
|/|;
1182 if ($media && $media eq 'cdrom') {
1183 $file = "local:iso/$file";
1185 $file = "local:$vmid/$file";
1192 sub verify_media_type
{
1193 my ($opt, $vtype, $media) = @_;
1198 if ($media eq 'disk') {
1200 } elsif ($media eq 'cdrom') {
1203 die "internal error";
1206 return if ($vtype eq $etype);
1208 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1211 sub cleanup_drive_path
{
1212 my ($opt, $storecfg, $drive) = @_;
1214 # try to convert filesystem paths to volume IDs
1216 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1217 ($drive->{file
} !~ m
|^/dev/.+|) &&
1218 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1219 ($drive->{file
} !~ m/^\d+$/)) {
1220 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1221 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1222 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1223 verify_media_type
($opt, $vtype, $drive->{media
});
1224 $drive->{file
} = $volid;
1227 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1230 sub parse_hotplug_features
{
1235 return $res if $data eq '0';
1237 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1239 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1240 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1243 die "invalid hotplug feature '$feature'\n";
1249 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1250 sub pve_verify_hotplug_features
{
1251 my ($value, $noerr) = @_;
1253 return $value if parse_hotplug_features
($value);
1255 return undef if $noerr;
1257 die "unable to parse hotplug option\n";
1260 # ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
1261 # [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
1262 # [,rerror=ignore|report|stop][,werror=enospc|ignore|report|stop]
1263 # [,aio=native|threads][,discard=ignore|on][,detect_zeroes=on|off]
1264 # [,iothread=on][,serial=serial][,model=model]
1267 my ($key, $data) = @_;
1269 my ($interface, $index);
1271 if ($key =~ m/^([^\d]+)(\d+)$/) {
1278 my $desc = $key =~ /^unused\d+$/ ?
$alldrive_fmt
1279 : $confdesc->{$key}->{format
};
1281 warn "invalid drive key: $key\n";
1284 my $res = eval { PVE
::JSONSchema
::parse_property_string
($desc, $data) };
1285 return undef if !$res;
1286 $res->{interface
} = $interface;
1287 $res->{index} = $index;
1290 foreach my $opt (qw(bps bps_rd bps_wr)) {
1291 if (my $bps = defined(delete $res->{$opt})) {
1292 if (defined($res->{"m$opt"})) {
1293 warn "both $opt and m$opt specified\n";
1297 $res->{"m$opt"} = sprintf("%.3f", $bps / (1024*1024.0));
1300 return undef if $error;
1302 return undef if $res->{mbps_rd
} && $res->{mbps
};
1303 return undef if $res->{mbps_wr
} && $res->{mbps
};
1304 return undef if $res->{iops_rd
} && $res->{iops
};
1305 return undef if $res->{iops_wr
} && $res->{iops
};
1307 if ($res->{media
} && ($res->{media
} eq 'cdrom')) {
1308 return undef if $res->{snapshot
} || $res->{trans
} || $res->{format
};
1309 return undef if $res->{heads
} || $res->{secs
} || $res->{cyls
};
1310 return undef if $res->{interface
} eq 'virtio';
1313 if (my $size = $res->{size
}) {
1314 return undef if !defined($res->{size
} = PVE
::JSONSchema
::parse_size
($size));
1321 my ($vmid, $drive) = @_;
1322 my $data = { %$drive };
1323 delete $data->{$_} for qw(index interface);
1324 return PVE
::JSONSchema
::print_property_string
($data, $alldrive_fmt);
1328 my($fh, $noerr) = @_;
1331 my $SG_GET_VERSION_NUM = 0x2282;
1333 my $versionbuf = "\x00" x
8;
1334 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1336 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1339 my $version = unpack("I", $versionbuf);
1340 if ($version < 30000) {
1341 die "scsi generic interface too old\n" if !$noerr;
1345 my $buf = "\x00" x
36;
1346 my $sensebuf = "\x00" x
8;
1347 my $cmd = pack("C x3 C x1", 0x12, 36);
1349 # see /usr/include/scsi/sg.h
1350 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";
1352 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1353 length($sensebuf), 0, length($buf), $buf,
1354 $cmd, $sensebuf, 6000);
1356 $ret = ioctl($fh, $SG_IO, $packet);
1358 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1362 my @res = unpack($sg_io_hdr_t, $packet);
1363 if ($res[17] || $res[18]) {
1364 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1369 (my $byte0, my $byte1, $res->{vendor
},
1370 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1372 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1373 $res->{type
} = $byte0 & 31;
1381 my $fh = IO
::File-
>new("+<$path") || return undef;
1382 my $res = scsi_inquiry
($fh, 1);
1388 sub machine_type_is_q35
{
1391 return $conf->{machine
} && ($conf->{machine
} =~ m/q35/) ?
1 : 0;
1394 sub print_tabletdevice_full
{
1397 my $q35 = machine_type_is_q35
($conf);
1399 # we use uhci for old VMs because tablet driver was buggy in older qemu
1400 my $usbbus = $q35 ?
"ehci" : "uhci";
1402 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1405 sub print_drivedevice_full
{
1406 my ($storecfg, $conf, $vmid, $drive, $bridges) = @_;
1411 if ($drive->{interface
} eq 'virtio') {
1412 my $pciaddr = print_pci_addr
("$drive->{interface}$drive->{index}", $bridges);
1413 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1414 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread
};
1415 } elsif ($drive->{interface
} eq 'scsi') {
1417 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1418 my $unit = $drive->{index} % $maxdev;
1419 my $devicetype = 'hd';
1421 if (drive_is_cdrom
($drive)) {
1424 if ($drive->{file
} =~ m
|^/|) {
1425 $path = $drive->{file
};
1426 if (my $info = path_is_scsi
($path)) {
1427 if ($info->{type
} == 0) {
1428 $devicetype = 'block';
1429 } elsif ($info->{type
} == 1) { # tape
1430 $devicetype = 'generic';
1434 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1437 if($path =~ m/^iscsi\:\/\
//){
1438 $devicetype = 'generic';
1442 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1443 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1445 $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}";
1448 } elsif ($drive->{interface
} eq 'ide'){
1450 my $controller = int($drive->{index} / $maxdev);
1451 my $unit = $drive->{index} % $maxdev;
1452 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1454 $device = "ide-$devicetype,bus=ide.$controller,unit=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1455 if ($devicetype eq 'hd' && (my $model = $drive->{model
})) {
1456 $model = URI
::Escape
::uri_unescape
($model);
1457 $device .= ",model=$model";
1459 } elsif ($drive->{interface
} eq 'sata'){
1460 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
1461 my $unit = $drive->{index} % $MAX_SATA_DISKS;
1462 $device = "ide-drive,bus=ahci$controller.$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1463 } elsif ($drive->{interface
} eq 'usb') {
1465 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1467 die "unsupported interface type";
1470 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1475 sub get_initiator_name
{
1478 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return undef;
1479 while (defined(my $line = <$fh>)) {
1480 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1489 sub print_drive_full
{
1490 my ($storecfg, $vmid, $drive) = @_;
1493 my $volid = $drive->{file
};
1496 if (drive_is_cdrom
($drive)) {
1497 $path = get_iso_path
($storecfg, $vmid, $volid);
1499 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1501 $path = PVE
::Storage
::path
($storecfg, $volid);
1502 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1503 $format = qemu_img_format
($scfg, $volname);
1511 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);
1512 foreach my $o (@qemu_drive_options) {
1513 $opts .= ",$o=$drive->{$o}" if $drive->{$o};
1515 if (my $serial = $drive->{serial
}) {
1516 $serial = URI
::Escape
::uri_unescape
($serial);
1517 $opts .= ",serial=$serial";
1520 $opts .= ",format=$format" if $format && !$drive->{format
};
1522 foreach my $o (qw(bps bps_rd bps_wr)) {
1523 my $v = $drive->{"m$o"};
1524 $opts .= ",$o=" . int($v*1024*1024) if $v;
1527 my $cache_direct = 0;
1529 if (my $cache = $drive->{cache
}) {
1530 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1531 } elsif (!drive_is_cdrom
($drive)) {
1532 $opts .= ",cache=none";
1536 # aio native works only with O_DIRECT
1537 if (!$drive->{aio
}) {
1539 $opts .= ",aio=native";
1541 $opts .= ",aio=threads";
1545 if (!drive_is_cdrom
($drive)) {
1547 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1548 $detectzeroes = 'off';
1549 } elsif ($drive->{discard
}) {
1550 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1552 # This used to be our default with discard not being specified:
1553 $detectzeroes = 'on';
1555 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1558 my $pathinfo = $path ?
"file=$path," : '';
1560 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1563 sub print_netdevice_full
{
1564 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files) = @_;
1566 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
1568 my $device = $net->{model
};
1569 if ($net->{model
} eq 'virtio') {
1570 $device = 'virtio-net-pci';
1573 my $pciaddr = print_pci_addr
("$netid", $bridges);
1574 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1575 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1576 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1577 my $vectors = $net->{queues
} * 2 + 2;
1578 $tmpstr .= ",vectors=$vectors,mq=on";
1580 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1582 if ($use_old_bios_files) {
1584 if ($device eq 'virtio-net-pci') {
1585 $romfile = 'pxe-virtio.rom';
1586 } elsif ($device eq 'e1000') {
1587 $romfile = 'pxe-e1000.rom';
1588 } elsif ($device eq 'ne2k') {
1589 $romfile = 'pxe-ne2k_pci.rom';
1590 } elsif ($device eq 'pcnet') {
1591 $romfile = 'pxe-pcnet.rom';
1592 } elsif ($device eq 'rtl8139') {
1593 $romfile = 'pxe-rtl8139.rom';
1595 $tmpstr .= ",romfile=$romfile" if $romfile;
1601 sub print_netdev_full
{
1602 my ($vmid, $conf, $net, $netid, $hotplug) = @_;
1605 if ($netid =~ m/^net(\d+)$/) {
1609 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1611 my $ifname = "tap${vmid}i$i";
1613 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1614 die "interface name '$ifname' is too long (max 15 character)\n"
1615 if length($ifname) >= 16;
1617 my $vhostparam = '';
1618 $vhostparam = ',vhost=on' if $kernel_has_vhost_net && $net->{model
} eq 'virtio';
1620 my $vmname = $conf->{name
} || "vm$vmid";
1623 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1625 if ($net->{bridge
}) {
1626 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1628 $netdev = "type=user,id=$netid,hostname=$vmname";
1631 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1636 sub drive_is_cdrom
{
1639 return $drive && $drive->{media
} && ($drive->{media
} eq 'cdrom');
1643 sub parse_number_sets
{
1646 foreach my $part (split(/;/, $set)) {
1647 if ($part =~ /^\s*(\d+)(?:-(\d+))?\s*$/) {
1648 die "invalid range: $part ($2 < $1)\n" if defined($2) && $2 < $1;
1649 push @$res, [ $1, $2 ];
1651 die "invalid range: $part\n";
1660 my $res = PVE
::JSONSchema
::parse_property_string
($numa_fmt, $data);
1661 $res->{cpus
} = parse_number_sets
($res->{cpus
}) if defined($res->{cpus
});
1662 $res->{hostnodes
} = parse_number_sets
($res->{hostnodes
}) if defined($res->{hostnodes
});
1669 return undef if !$value;
1671 my $res = PVE
::JSONSchema
::parse_property_string
($hostpci_fmt, $value);
1673 my @idlist = split(/;/, $res->{host
});
1674 delete $res->{host
};
1675 foreach my $id (@idlist) {
1676 if ($id =~ /^$PCIRE$/) {
1677 push @{$res->{pciid
}}, { id
=> $1, function
=> ($2//'0') };
1679 # should have been caught by parse_property_string already
1680 die "failed to parse PCI id: $id\n";
1686 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1690 my $res = eval { PVE
::JSONSchema
::parse_property_string
($net_fmt, $data) };
1695 if (!defined($res->{macaddr
})) {
1696 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
1697 $res->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
});
1705 return PVE
::JSONSchema
::print_property_string
($net, $net_fmt);
1708 sub add_random_macs
{
1709 my ($settings) = @_;
1711 foreach my $opt (keys %$settings) {
1712 next if $opt !~ m/^net(\d+)$/;
1713 my $net = parse_net
($settings->{$opt});
1715 $settings->{$opt} = print_net
($net);
1719 sub vm_is_volid_owner
{
1720 my ($storecfg, $vmid, $volid) = @_;
1722 if ($volid !~ m
|^/|) {
1724 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
1725 if ($owner && ($owner == $vmid)) {
1733 sub split_flagged_list
{
1734 my $text = shift || '';
1735 $text =~ s/[,;]/ /g;
1737 return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
1740 sub join_flagged_list
{
1741 my ($how, $lst) = @_;
1742 join $how, map { $lst->{$_} . $_ } keys %$lst;
1745 sub vmconfig_delete_pending_option
{
1746 my ($conf, $key, $force) = @_;
1748 delete $conf->{pending
}->{$key};
1749 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
1750 $pending_delete_hash->{$key} = $force ?
'!' : '';
1751 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
1754 sub vmconfig_undelete_pending_option
{
1755 my ($conf, $key) = @_;
1757 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
1758 delete $pending_delete_hash->{$key};
1760 if (%$pending_delete_hash) {
1761 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
1763 delete $conf->{pending
}->{delete};
1767 sub vmconfig_register_unused_drive
{
1768 my ($storecfg, $vmid, $conf, $drive) = @_;
1770 if (!drive_is_cdrom
($drive)) {
1771 my $volid = $drive->{file
};
1772 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
1773 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
1778 sub vmconfig_cleanup_pending
{
1781 # remove pending changes when nothing changed
1783 foreach my $opt (keys %{$conf->{pending
}}) {
1784 if (defined($conf->{$opt}) && ($conf->{pending
}->{$opt} eq $conf->{$opt})) {
1786 delete $conf->{pending
}->{$opt};
1790 my $current_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
1791 my $pending_delete_hash = {};
1792 while (my ($opt, $force) = each %$current_delete_hash) {
1793 if (defined($conf->{$opt})) {
1794 $pending_delete_hash->{$opt} = $force;
1800 if (%$pending_delete_hash) {
1801 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
1803 delete $conf->{pending
}->{delete};
1809 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
1813 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
1814 format_description
=> 'UUID',
1815 description
=> "Set SMBIOS1 UUID.",
1821 format_description
=> 'string',
1822 description
=> "Set SMBIOS1 version.",
1828 format_description
=> 'string',
1829 description
=> "Set SMBIOS1 serial number.",
1835 format_description
=> 'string',
1836 description
=> "Set SMBIOS1 manufacturer.",
1842 format_description
=> 'string',
1843 description
=> "Set SMBIOS1 product ID.",
1849 format_description
=> 'string',
1850 description
=> "Set SMBIOS1 SKU string.",
1856 format_description
=> 'string',
1857 description
=> "Set SMBIOS1 family string.",
1865 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_fmt, $data) };
1872 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_fmt);
1875 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_fmt);
1877 PVE
::JSONSchema
::register_format
('pve-qm-bootdisk', \
&verify_bootdisk
);
1878 sub verify_bootdisk
{
1879 my ($value, $noerr) = @_;
1881 return $value if is_valid_drivename
($value);
1883 return undef if $noerr;
1885 die "invalid boot disk '$value'\n";
1888 sub parse_watchdog
{
1891 return undef if !$value;
1893 my $res = eval { PVE
::JSONSchema
::parse_property_string
($watchdog_fmt, $value) };
1898 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
1899 sub verify_usb_device
{
1900 my ($value, $noerr) = @_;
1902 return $value if parse_usb_device
($value);
1904 return undef if $noerr;
1906 die "unable to parse usb device\n";
1909 # add JSON properties for create and set function
1910 sub json_config_properties
{
1913 foreach my $opt (keys %$confdesc) {
1914 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate';
1915 $prop->{$opt} = $confdesc->{$opt};
1922 my ($key, $value) = @_;
1924 die "unknown setting '$key'\n" if !$confdesc->{$key};
1926 my $type = $confdesc->{$key}->{type
};
1928 if (!defined($value)) {
1929 die "got undefined value\n";
1932 if ($value =~ m/[\n\r]/) {
1933 die "property contains a line feed\n";
1936 if ($type eq 'boolean') {
1937 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
1938 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
1939 die "type check ('boolean') failed - got '$value'\n";
1940 } elsif ($type eq 'integer') {
1941 return int($1) if $value =~ m/^(\d+)$/;
1942 die "type check ('integer') failed - got '$value'\n";
1943 } elsif ($type eq 'number') {
1944 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
1945 die "type check ('number') failed - got '$value'\n";
1946 } elsif ($type eq 'string') {
1947 if (my $fmt = $confdesc->{$key}->{format
}) {
1948 if ($fmt eq 'pve-qm-drive') {
1949 # special case - we need to pass $key to parse_drive()
1950 my $drive = parse_drive
($key, $value);
1951 return $value if $drive;
1952 die "unable to parse drive options\n";
1954 PVE
::JSONSchema
::check_format
($fmt, $value);
1957 $value =~ s/^\"(.*)\"$/$1/;
1960 die "internal error"
1964 sub check_iommu_support
{
1965 #fixme : need to check IOMMU support
1966 #http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM
1976 my $conf = PVE
::QemuConfig-
>config_file($vmid);
1977 utime undef, undef, $conf;
1981 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
1983 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
1985 my $conf = PVE
::QemuConfig-
>load_config($vmid);
1987 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
1989 # only remove disks owned by this VM
1990 foreach_drive
($conf, sub {
1991 my ($ds, $drive) = @_;
1993 return if drive_is_cdrom
($drive);
1995 my $volid = $drive->{file
};
1997 return if !$volid || $volid =~ m
|^/|;
1999 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
2000 return if !$path || !$owner || ($owner != $vmid);
2002 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2005 if ($keep_empty_config) {
2006 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
2011 # also remove unused disk
2013 my $dl = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
2016 PVE
::Storage
::foreach_volid
($dl, sub {
2017 my ($volid, $sid, $volname, $d) = @_;
2018 PVE
::Storage
::vdisk_free
($storecfg, $volid);
2027 sub parse_vm_config
{
2028 my ($filename, $raw) = @_;
2030 return undef if !defined($raw);
2033 digest
=> Digest
::SHA
::sha1_hex
($raw),
2038 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
2039 || die "got strange filename '$filename'";
2047 my @lines = split(/\n/, $raw);
2048 foreach my $line (@lines) {
2049 next if $line =~ m/^\s*$/;
2051 if ($line =~ m/^\[PENDING\]\s*$/i) {
2052 $section = 'pending';
2053 if (defined($descr)) {
2055 $conf->{description
} = $descr;
2058 $conf = $res->{$section} = {};
2061 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
2063 if (defined($descr)) {
2065 $conf->{description
} = $descr;
2068 $conf = $res->{snapshots
}->{$section} = {};
2072 if ($line =~ m/^\#(.*)\s*$/) {
2073 $descr = '' if !defined($descr);
2074 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2078 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2079 $descr = '' if !defined($descr);
2080 $descr .= PVE
::Tools
::decode_text
($2);
2081 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2082 $conf->{snapstate
} = $1;
2083 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2086 $conf->{$key} = $value;
2087 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2089 if ($section eq 'pending') {
2090 $conf->{delete} = $value; # we parse this later
2092 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2094 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(\S+)\s*$/) {
2097 eval { $value = check_type
($key, $value); };
2099 warn "vm $vmid - unable to parse value of '$key' - $@";
2101 my $fmt = $confdesc->{$key}->{format
};
2102 if ($fmt && $fmt eq 'pve-qm-drive') {
2103 my $v = parse_drive
($key, $value);
2104 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2105 $v->{file
} = $volid;
2106 $value = print_drive
($vmid, $v);
2108 warn "vm $vmid - unable to parse value of '$key'\n";
2113 if ($key eq 'cdrom') {
2114 $conf->{ide2
} = $value;
2116 $conf->{$key} = $value;
2122 if (defined($descr)) {
2124 $conf->{description
} = $descr;
2126 delete $res->{snapstate
}; # just to be sure
2131 sub write_vm_config
{
2132 my ($filename, $conf) = @_;
2134 delete $conf->{snapstate
}; # just to be sure
2136 if ($conf->{cdrom
}) {
2137 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2138 $conf->{ide2
} = $conf->{cdrom
};
2139 delete $conf->{cdrom
};
2142 # we do not use 'smp' any longer
2143 if ($conf->{sockets
}) {
2144 delete $conf->{smp
};
2145 } elsif ($conf->{smp
}) {
2146 $conf->{sockets
} = $conf->{smp
};
2147 delete $conf->{cores
};
2148 delete $conf->{smp
};
2151 my $used_volids = {};
2153 my $cleanup_config = sub {
2154 my ($cref, $pending, $snapname) = @_;
2156 foreach my $key (keys %$cref) {
2157 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2158 $key eq 'snapstate' || $key eq 'pending';
2159 my $value = $cref->{$key};
2160 if ($key eq 'delete') {
2161 die "propertry 'delete' is only allowed in [PENDING]\n"
2163 # fixme: check syntax?
2166 eval { $value = check_type
($key, $value); };
2167 die "unable to parse value of '$key' - $@" if $@;
2169 $cref->{$key} = $value;
2171 if (!$snapname && is_valid_drivename
($key)) {
2172 my $drive = parse_drive
($key, $value);
2173 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2178 &$cleanup_config($conf);
2180 &$cleanup_config($conf->{pending
}, 1);
2182 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2183 die "internal error" if $snapname eq 'pending';
2184 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2187 # remove 'unusedX' settings if we re-add a volume
2188 foreach my $key (keys %$conf) {
2189 my $value = $conf->{$key};
2190 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2191 delete $conf->{$key};
2195 my $generate_raw_config = sub {
2196 my ($conf, $pending) = @_;
2200 # add description as comment to top of file
2201 if (defined(my $descr = $conf->{description
})) {
2203 foreach my $cl (split(/\n/, $descr)) {
2204 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2207 $raw .= "#\n" if $pending;
2211 foreach my $key (sort keys %$conf) {
2212 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2213 $raw .= "$key: $conf->{$key}\n";
2218 my $raw = &$generate_raw_config($conf);
2220 if (scalar(keys %{$conf->{pending
}})){
2221 $raw .= "\n[PENDING]\n";
2222 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2225 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2226 $raw .= "\n[$snapname]\n";
2227 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2237 # we use static defaults from our JSON schema configuration
2238 foreach my $key (keys %$confdesc) {
2239 if (defined(my $default = $confdesc->{$key}->{default})) {
2240 $res->{$key} = $default;
2244 my $conf = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
2245 $res->{keyboard
} = $conf->{keyboard
} if $conf->{keyboard
};
2251 my $vmlist = PVE
::Cluster
::get_vmlist
();
2253 return $res if !$vmlist || !$vmlist->{ids
};
2254 my $ids = $vmlist->{ids
};
2256 foreach my $vmid (keys %$ids) {
2257 my $d = $ids->{$vmid};
2258 next if !$d->{node
} || $d->{node
} ne $nodename;
2259 next if !$d->{type
} || $d->{type
} ne 'qemu';
2260 $res->{$vmid}->{exists} = 1;
2265 # test if VM uses local resources (to prevent migration)
2266 sub check_local_resources
{
2267 my ($conf, $noerr) = @_;
2271 $loc_res = 1 if $conf->{hostusb
}; # old syntax
2272 $loc_res = 1 if $conf->{hostpci
}; # old syntax
2274 foreach my $k (keys %$conf) {
2275 next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2276 # sockets are safe: they will recreated be on the target side post-migrate
2277 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2278 $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2281 die "VM uses local resources\n" if $loc_res && !$noerr;
2286 # check if used storages are available on all nodes (use by migrate)
2287 sub check_storage_availability
{
2288 my ($storecfg, $conf, $node) = @_;
2290 foreach_drive
($conf, sub {
2291 my ($ds, $drive) = @_;
2293 my $volid = $drive->{file
};
2296 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2299 # check if storage is available on both nodes
2300 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2301 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2305 # list nodes where all VM images are available (used by has_feature API)
2307 my ($conf, $storecfg) = @_;
2309 my $nodelist = PVE
::Cluster
::get_nodelist
();
2310 my $nodehash = { map { $_ => 1 } @$nodelist };
2311 my $nodename = PVE
::INotify
::nodename
();
2313 foreach_drive
($conf, sub {
2314 my ($ds, $drive) = @_;
2316 my $volid = $drive->{file
};
2319 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2321 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2322 if ($scfg->{disable
}) {
2324 } elsif (my $avail = $scfg->{nodes
}) {
2325 foreach my $node (keys %$nodehash) {
2326 delete $nodehash->{$node} if !$avail->{$node};
2328 } elsif (!$scfg->{shared
}) {
2329 foreach my $node (keys %$nodehash) {
2330 delete $nodehash->{$node} if $node ne $nodename
2340 my ($pidfile, $pid) = @_;
2342 my $fh = IO
::File-
>new("/proc/$pid/cmdline", "r");
2346 return undef if !$line;
2347 my @param = split(/\0/, $line);
2349 my $cmd = $param[0];
2350 return if !$cmd || ($cmd !~ m
|kvm
$| && $cmd !~ m
|qemu-system-x86_64
$|);
2352 for (my $i = 0; $i < scalar (@param); $i++) {
2355 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2356 my $p = $param[$i+1];
2357 return 1 if $p && ($p eq $pidfile);
2366 my ($vmid, $nocheck, $node) = @_;
2368 my $filename = PVE
::QemuConfig-
>config_file($vmid, $node);
2370 die "unable to find configuration file for VM $vmid - no such machine\n"
2371 if !$nocheck && ! -f
$filename;
2373 my $pidfile = pidfile_name
($vmid);
2375 if (my $fd = IO
::File-
>new("<$pidfile")) {
2380 my $mtime = $st->mtime;
2381 if ($mtime > time()) {
2382 warn "file '$filename' modified in future\n";
2385 if ($line =~ m/^(\d+)$/) {
2387 if (check_cmdline
($pidfile, $pid)) {
2388 if (my $pinfo = PVE
::ProcFSTools
::check_process_running
($pid)) {
2400 my $vzlist = config_list
();
2402 my $fd = IO
::Dir-
>new($var_run_tmpdir) || return $vzlist;
2404 while (defined(my $de = $fd->read)) {
2405 next if $de !~ m/^(\d+)\.pid$/;
2407 next if !defined($vzlist->{$vmid});
2408 if (my $pid = check_running
($vmid)) {
2409 $vzlist->{$vmid}->{pid
} = $pid;
2417 my ($storecfg, $conf) = @_;
2419 my $bootdisk = $conf->{bootdisk
};
2420 return undef if !$bootdisk;
2421 return undef if !is_valid_drivename
($bootdisk);
2423 return undef if !$conf->{$bootdisk};
2425 my $drive = parse_drive
($bootdisk, $conf->{$bootdisk});
2426 return undef if !defined($drive);
2428 return undef if drive_is_cdrom
($drive);
2430 my $volid = $drive->{file
};
2431 return undef if !$volid;
2433 return $drive->{size
};
2436 my $last_proc_pid_stat;
2438 # get VM status information
2439 # This must be fast and should not block ($full == false)
2440 # We only query KVM using QMP if $full == true (this can be slow)
2442 my ($opt_vmid, $full) = @_;
2446 my $storecfg = PVE
::Storage
::config
();
2448 my $list = vzlist
();
2449 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2451 my $cpucount = $cpuinfo->{cpus
} || 1;
2453 foreach my $vmid (keys %$list) {
2454 next if $opt_vmid && ($vmid ne $opt_vmid);
2456 my $cfspath = PVE
::QemuConfig-
>cfs_config_path($vmid);
2457 my $conf = PVE
::Cluster
::cfs_read_file
($cfspath) || {};
2460 $d->{pid
} = $list->{$vmid}->{pid
};
2462 # fixme: better status?
2463 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
2465 my $size = disksize
($storecfg, $conf);
2466 if (defined($size)) {
2467 $d->{disk
} = 0; # no info available
2468 $d->{maxdisk
} = $size;
2474 $d->{cpus
} = ($conf->{sockets
} || 1) * ($conf->{cores
} || 1);
2475 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
2476 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
2478 $d->{name
} = $conf->{name
} || "VM $vmid";
2479 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024) : 0;
2481 if ($conf->{balloon
}) {
2482 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
2483 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
} : 1000;
2494 $d->{diskwrite
} = 0;
2496 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
2501 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
2502 foreach my $dev (keys %$netdev) {
2503 next if $dev !~ m/^tap([1-9]\d*)i/;
2505 my $d = $res->{$vmid};
2508 $d->{netout
} += $netdev->{$dev}->{receive
};
2509 $d->{netin
} += $netdev->{$dev}->{transmit
};
2512 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
2513 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
2518 my $ctime = gettimeofday
;
2520 foreach my $vmid (keys %$list) {
2522 my $d = $res->{$vmid};
2523 my $pid = $d->{pid
};
2526 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
2527 next if !$pstat; # not running
2529 my $used = $pstat->{utime} + $pstat->{stime
};
2531 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
2533 if ($pstat->{vsize
}) {
2534 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
2537 my $old = $last_proc_pid_stat->{$pid};
2539 $last_proc_pid_stat->{$pid} = {
2547 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
2549 if ($dtime > 1000) {
2550 my $dutime = $used - $old->{used
};
2552 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
2553 $last_proc_pid_stat->{$pid} = {
2559 $d->{cpu
} = $old->{cpu
};
2563 return $res if !$full;
2565 my $qmpclient = PVE
::QMPClient-
>new();
2567 my $ballooncb = sub {
2568 my ($vmid, $resp) = @_;
2570 my $info = $resp->{'return'};
2571 return if !$info->{max_mem
};
2573 my $d = $res->{$vmid};
2575 # use memory assigned to VM
2576 $d->{maxmem
} = $info->{max_mem
};
2577 $d->{balloon
} = $info->{actual
};
2579 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
2580 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
2581 $d->{freemem
} = $info->{free_mem
};
2584 $d->{ballooninfo
} = $info;
2587 my $blockstatscb = sub {
2588 my ($vmid, $resp) = @_;
2589 my $data = $resp->{'return'} || [];
2590 my $totalrdbytes = 0;
2591 my $totalwrbytes = 0;
2593 for my $blockstat (@$data) {
2594 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
2595 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
2597 $blockstat->{device
} =~ s/drive-//;
2598 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
2600 $res->{$vmid}->{diskread
} = $totalrdbytes;
2601 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
2604 my $statuscb = sub {
2605 my ($vmid, $resp) = @_;
2607 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
2608 # this fails if ballon driver is not loaded, so this must be
2609 # the last commnand (following command are aborted if this fails).
2610 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
2612 my $status = 'unknown';
2613 if (!defined($status = $resp->{'return'}->{status
})) {
2614 warn "unable to get VM status\n";
2618 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
2621 foreach my $vmid (keys %$list) {
2622 next if $opt_vmid && ($vmid ne $opt_vmid);
2623 next if !$res->{$vmid}->{pid
}; # not running
2624 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
2627 $qmpclient->queue_execute(undef, 1);
2629 foreach my $vmid (keys %$list) {
2630 next if $opt_vmid && ($vmid ne $opt_vmid);
2631 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
2638 my ($conf, $func, @param) = @_;
2640 foreach my $ds (valid_drive_names
()) {
2641 next if !defined($conf->{$ds});
2643 my $drive = parse_drive
($ds, $conf->{$ds});
2646 &$func($ds, $drive, @param);
2651 my ($conf, $func, @param) = @_;
2655 my $test_volid = sub {
2656 my ($volid, $is_cdrom) = @_;
2660 $volhash->{$volid} = $is_cdrom || 0;
2663 foreach_drive
($conf, sub {
2664 my ($ds, $drive) = @_;
2665 &$test_volid($drive->{file
}, drive_is_cdrom
($drive));
2668 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2669 my $snap = $conf->{snapshots
}->{$snapname};
2670 &$test_volid($snap->{vmstate
}, 0);
2671 foreach_drive
($snap, sub {
2672 my ($ds, $drive) = @_;
2673 &$test_volid($drive->{file
}, drive_is_cdrom
($drive));
2677 foreach my $volid (keys %$volhash) {
2678 &$func($volid, $volhash->{$volid}, @param);
2682 sub vga_conf_has_spice
{
2685 return 0 if !$vga || $vga !~ m/^qxl([234])?$/;
2690 sub config_to_command
{
2691 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
2694 my $globalFlags = [];
2695 my $machineFlags = [];
2701 my $kvmver = kvm_user_version
();
2702 my $vernum = 0; # unknown
2703 my $ostype = $conf->{ostype
};
2704 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
2705 $vernum = $1*1000000+$2*1000;
2706 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
2707 $vernum = $1*1000000+$2*1000+$3;
2710 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
2712 my $have_ovz = -f
'/proc/vz/vestat';
2714 my $q35 = machine_type_is_q35
($conf);
2715 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
2716 my $machine_type = $forcemachine || $conf->{machine
};
2717 my $use_old_bios_files = undef;
2718 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
2720 my $cpuunits = defined($conf->{cpuunits
}) ?
2721 $conf->{cpuunits
} : $defaults->{cpuunits
};
2723 push @$cmd, '/usr/bin/kvm';
2725 push @$cmd, '-id', $vmid;
2729 my $qmpsocket = qmp_socket
($vmid);
2730 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
2731 push @$cmd, '-mon', "chardev=qmp,mode=control";
2734 push @$cmd, '-pidfile' , pidfile_name
($vmid);
2736 push @$cmd, '-daemonize';
2738 if ($conf->{smbios1
}) {
2739 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
2742 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
2743 my $ovmfvar = "OVMF_VARS-pure-efi.fd";
2744 my $ovmfvar_src = "/usr/share/kvm/$ovmfvar";
2745 my $ovmfvar_dst = "/tmp/$vmid-$ovmfvar";
2746 PVE
::Tools
::file_copy
($ovmfvar_src, $ovmfvar_dst, 256*1024);
2747 push @$cmd, '-drive', "if=pflash,format=raw,readonly,file=/usr/share/kvm/OVMF-pure-efi.fd";
2748 push @$cmd, '-drive', "if=pflash,format=raw,file=$ovmfvar_dst";
2752 # add usb controllers
2753 my @usbcontrollers = PVE
::QemuServer
::USB
::get_usb_controllers
($conf, $bridges, $q35, $usbdesc->{format
}, $MAX_USB_DEVICES);
2754 push @$devices, @usbcontrollers if @usbcontrollers;
2755 my $vga = $conf->{vga
};
2757 my $qxlnum = vga_conf_has_spice
($vga);
2758 $vga = 'qxl' if $qxlnum;
2761 if ($conf->{ostype
} && ($conf->{ostype
} eq 'win8' ||
2762 $conf->{ostype
} eq 'win7' ||
2763 $conf->{ostype
} eq 'w2k8')) {
2770 # enable absolute mouse coordinates (needed by vnc)
2772 if (defined($conf->{tablet
})) {
2773 $tablet = $conf->{tablet
};
2775 $tablet = $defaults->{tablet
};
2776 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
2777 $tablet = 0 if $vga =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
2780 push @$devices, '-device', print_tabletdevice_full
($conf) if $tablet;
2784 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
2785 my $d = parse_hostpci
($conf->{"hostpci$i"});
2788 my $pcie = $d->{pcie
};
2790 die "q35 machine model is not enabled" if !$q35;
2791 $pciaddr = print_pcie_addr
("hostpci$i");
2793 $pciaddr = print_pci_addr
("hostpci$i", $bridges);
2796 my $rombar = defined($d->{rombar
}) && !$d->{rombar
} ?
',rombar=0' : '';
2798 if ($d->{'x-vga'}) {
2799 $xvga = ',x-vga=on';
2802 if ($ostype eq 'win7' || $ostype eq 'win8' || $ostype eq 'w2k8') {
2803 push @$cpuFlags , 'hv_vendor_id=proxmox';
2805 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
2809 my $pcidevices = $d->{pciid
};
2810 my $multifunction = 1 if @$pcidevices > 1;
2813 foreach my $pcidevice (@$pcidevices) {
2815 my $id = "hostpci$i";
2816 $id .= ".$j" if $multifunction;
2817 my $addr = $pciaddr;
2818 $addr .= ".$j" if $multifunction;
2819 my $devicestr = "vfio-pci,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
2822 $devicestr .= "$rombar$xvga";
2823 $devicestr .= ",multifunction=on" if $multifunction;
2826 push @$devices, '-device', $devicestr;
2832 my @usbdevices = PVE
::QemuServer
::USB
::get_usb_devices
($conf, $usbdesc->{format
}, $MAX_USB_DEVICES);
2833 push @$devices, @usbdevices if @usbdevices;
2835 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
2836 if (my $path = $conf->{"serial$i"}) {
2837 if ($path eq 'socket') {
2838 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
2839 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
2840 push @$devices, '-device', "isa-serial,chardev=serial$i";
2842 die "no such serial device\n" if ! -c
$path;
2843 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
2844 push @$devices, '-device', "isa-serial,chardev=serial$i";
2850 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
2851 if (my $path = $conf->{"parallel$i"}) {
2852 die "no such parallel device\n" if ! -c
$path;
2853 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
2854 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
2855 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
2859 my $vmname = $conf->{name
} || "vm$vmid";
2861 push @$cmd, '-name', $vmname;
2864 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
2865 $sockets = $conf->{sockets
} if $conf->{sockets
};
2867 my $cores = $conf->{cores
} || 1;
2869 my $maxcpus = $sockets * $cores;
2871 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
2873 my $allowed_vcpus = $cpuinfo->{cpus
};
2875 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
2876 if ($allowed_vcpus < $maxcpus);
2878 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
2880 push @$cmd, '-nodefaults';
2882 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
2884 my $bootindex_hash = {};
2886 foreach my $o (split(//, $bootorder)) {
2887 $bootindex_hash->{$o} = $i*100;
2891 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000";
2893 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
2895 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
2897 push @$cmd, '-vga', $vga if $vga && $vga !~ m/^serial\d+$/; # for kvm 77 and later
2899 if ($vga && $vga !~ m/^serial\d+$/ && $vga ne 'none'){
2900 my $socket = vnc_socket
($vmid);
2901 push @$cmd, '-vnc', "unix:$socket,x509,password";
2903 push @$cmd, '-nographic';
2907 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
2909 my $nokvm = defined($conf->{kvm
}) && $conf->{kvm
} == 0 ?
1 : 0;
2910 my $useLocaltime = $conf->{localtime};
2913 # other, wxp, w2k, w2k3, w2k8, wvista, win7, win8, l24, l26, solaris
2915 if ($ostype =~ m/^w/) { # windows
2916 $useLocaltime = 1 if !defined($conf->{localtime});
2918 # use time drift fix when acpi is enabled
2919 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
2920 $tdf = 1 if !defined($conf->{tdf
});
2924 if ($ostype eq 'win7' || $ostype eq 'win8' || $ostype eq 'w2k8' ||
2925 $ostype eq 'wvista') {
2926 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
2927 push @$cmd, '-no-hpet';
2928 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
2929 push @$cpuFlags , 'hv_spinlocks=0x1fff' if !$nokvm;
2930 push @$cpuFlags , 'hv_vapic' if !$nokvm;
2931 push @$cpuFlags , 'hv_time' if !$nokvm;
2933 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 6)) {
2934 push @$cpuFlags , 'hv_reset' if !$nokvm;
2935 push @$cpuFlags , 'hv_vpindex' if !$nokvm;
2936 push @$cpuFlags , 'hv_runtime' if !$nokvm;
2940 push @$cpuFlags , 'hv_spinlocks=0xffff' if !$nokvm;
2944 if ($ostype eq 'win7' || $ostype eq 'win8') {
2945 push @$cpuFlags , 'hv_relaxed' if !$nokvm;
2949 push @$rtcFlags, 'driftfix=slew' if $tdf;
2952 push @$machineFlags, 'accel=tcg';
2954 die "No accelerator found!\n" if !$cpuinfo->{hvm
};
2957 if ($machine_type) {
2958 push @$machineFlags, "type=${machine_type}";
2961 if ($conf->{startdate
}) {
2962 push @$rtcFlags, "base=$conf->{startdate}";
2963 } elsif ($useLocaltime) {
2964 push @$rtcFlags, 'base=localtime';
2967 my $cpu = $nokvm ?
"qemu64" : "kvm64";
2968 if (my $cputype = $conf->{cpu
}) {
2969 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpu_fmt, $cputype)
2970 or die "Cannot parse cpu description: $cputype\n";
2971 $cpu = $cpuconf->{cputype
};
2972 $kvm_off = 1 if $cpuconf->{hidden
};
2975 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64';
2977 push @$cpuFlags , '-x2apic'
2978 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
2980 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
2982 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
2984 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
2986 push @$cpuFlags , '+kvm_pv_unhalt' if !$nokvm;
2987 push @$cpuFlags , '+kvm_pv_eoi' if !$nokvm;
2990 push @$cpuFlags, 'enforce' if $cpu ne 'host' && !$nokvm;
2992 push @$cpuFlags, 'kvm=off' if $kvm_off;
2994 my $cpu_vendor = $cpu_vendor_list->{$cpu} ||
2995 die "internal error"; # should not happen
2997 push @$cpuFlags, "vendor=${cpu_vendor}"
2998 if $cpu_vendor ne 'default';
3000 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3002 push @$cmd, '-cpu', $cpu;
3004 PVE
::QemuServer
::Memory
::config
($conf, $vmid, $sockets, $cores, $defaults, $hotplug_features, $cmd);
3006 push @$cmd, '-S' if $conf->{freeze
};
3008 # set keyboard layout
3009 my $kb = $conf->{keyboard
} || $defaults->{keyboard
};
3010 push @$cmd, '-k', $kb if $kb;
3013 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3014 #push @$cmd, '-soundhw', 'es1370';
3015 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3017 if($conf->{agent
}) {
3018 my $qgasocket = qmp_socket
($vmid, 1);
3019 my $pciaddr = print_pci_addr
("qga0", $bridges);
3020 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3021 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3022 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3029 if ($conf->{ostype
} && $conf->{ostype
} =~ m/^w/){
3030 for(my $i = 1; $i < $qxlnum; $i++){
3031 my $pciaddr = print_pci_addr
("vga$i", $bridges);
3032 push @$cmd, '-device', "qxl,id=vga$i,ram_size=67108864,vram_size=33554432$pciaddr";
3035 # assume other OS works like Linux
3036 push @$cmd, '-global', 'qxl-vga.ram_size=134217728';
3037 push @$cmd, '-global', 'qxl-vga.vram_size=67108864';
3041 my $pciaddr = print_pci_addr
("spice", $bridges);
3043 my $nodename = PVE
::INotify
::nodename
();
3044 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3045 $spice_port = PVE
::Tools
::next_spice_port
($pfamily);
3047 push @$devices, '-spice', "tls-port=${spice_port},addr=localhost,tls-ciphers=DES-CBC3-SHA,seamless-migration=on";
3049 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3050 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3051 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3054 # enable balloon by default, unless explicitly disabled
3055 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3056 $pciaddr = print_pci_addr
("balloon0", $bridges);
3057 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3060 if ($conf->{watchdog
}) {
3061 my $wdopts = parse_watchdog
($conf->{watchdog
});
3062 $pciaddr = print_pci_addr
("watchdog", $bridges);
3063 my $watchdog = $wdopts->{model
} || 'i6300esb';
3064 push @$devices, '-device', "$watchdog$pciaddr";
3065 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3069 my $scsicontroller = {};
3070 my $ahcicontroller = {};
3071 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3073 # Add iscsi initiator name if available
3074 if (my $initiator = get_initiator_name
()) {
3075 push @$devices, '-iscsi', "initiator-name=$initiator";
3078 foreach_drive
($conf, sub {
3079 my ($ds, $drive) = @_;
3081 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3082 push @$vollist, $drive->{file
};
3085 $use_virtio = 1 if $ds =~ m/^virtio/;
3087 if (drive_is_cdrom
($drive)) {
3088 if ($bootindex_hash->{d
}) {
3089 $drive->{bootindex
} = $bootindex_hash->{d
};
3090 $bootindex_hash->{d
} += 1;
3093 if ($bootindex_hash->{c
}) {
3094 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3095 $bootindex_hash->{c
} += 1;
3099 if($drive->{interface
} eq 'virtio'){
3100 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3103 if ($drive->{interface
} eq 'scsi') {
3105 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3107 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges);
3108 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3111 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3112 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3113 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3114 } elsif ($drive->{iothread
}) {
3115 warn "iothread is only valid with virtio disk or virtio-scsi-single controller, ignoring\n";
3119 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3120 $queues = ",num_queues=$drive->{queues}";
3123 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3124 $scsicontroller->{$controller}=1;
3127 if ($drive->{interface
} eq 'sata') {
3128 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3129 $pciaddr = print_pci_addr
("ahci$controller", $bridges);
3130 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3131 $ahcicontroller->{$controller}=1;
3134 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3135 push @$devices, '-drive',$drive_cmd;
3136 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges);
3139 for (my $i = 0; $i < $MAX_NETS; $i++) {
3140 next if !$conf->{"net$i"};
3141 my $d = parse_net
($conf->{"net$i"});
3144 $use_virtio = 1 if $d->{model
} eq 'virtio';
3146 if ($bootindex_hash->{n
}) {
3147 $d->{bootindex
} = $bootindex_hash->{n
};
3148 $bootindex_hash->{n
} += 1;
3151 my $netdevfull = print_netdev_full
($vmid,$conf,$d,"net$i");
3152 push @$devices, '-netdev', $netdevfull;
3154 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files);
3155 push @$devices, '-device', $netdevicefull;
3160 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3165 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3167 while (my ($k, $v) = each %$bridges) {
3168 $pciaddr = print_pci_addr
("pci.$k");
3169 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3174 if ($conf->{args
}) {
3175 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3179 push @$cmd, @$devices;
3180 push @$cmd, '-rtc', join(',', @$rtcFlags)
3181 if scalar(@$rtcFlags);
3182 push @$cmd, '-machine', join(',', @$machineFlags)
3183 if scalar(@$machineFlags);
3184 push @$cmd, '-global', join(',', @$globalFlags)
3185 if scalar(@$globalFlags);
3187 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3192 return "${var_run_tmpdir}/$vmid.vnc";
3198 my $res = vm_mon_cmd
($vmid, 'query-spice');
3200 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3204 my ($vmid, $qga) = @_;
3205 my $sockettype = $qga ?
'qga' : 'qmp';
3206 return "${var_run_tmpdir}/$vmid.$sockettype";
3211 return "${var_run_tmpdir}/$vmid.pid";
3214 sub vm_devices_list
{
3217 my $res = vm_mon_cmd
($vmid, 'query-pci');
3219 foreach my $pcibus (@$res) {
3220 foreach my $device (@{$pcibus->{devices
}}) {
3221 next if !$device->{'qdev_id'};
3222 if ($device->{'pci_bridge'}) {
3223 $devices->{$device->{'qdev_id'}} = 1;
3224 foreach my $bridge_device (@{$device->{'pci_bridge'}->{devices
}}) {
3225 next if !$bridge_device->{'qdev_id'};
3226 $devices->{$bridge_device->{'qdev_id'}} = 1;
3227 $devices->{$device->{'qdev_id'}}++;
3230 $devices->{$device->{'qdev_id'}} = 1;
3235 my $resblock = vm_mon_cmd
($vmid, 'query-block');
3236 foreach my $block (@$resblock) {
3237 if($block->{device
} =~ m/^drive-(\S+)/){
3242 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
3243 foreach my $mice (@$resmice) {
3244 if ($mice->{name
} eq 'QEMU HID Tablet') {
3245 $devices->{tablet
} = 1;
3250 # for usb devices there is no query-usb
3251 # but we can iterate over the entries in
3252 # qom-list path=/machine/peripheral
3253 my $resperipheral = vm_mon_cmd
($vmid, 'qom-list', path
=> '/machine/peripheral');
3254 foreach my $per (@$resperipheral) {
3255 if ($per->{name
} =~ m/^usb\d+$/) {
3256 $devices->{$per->{name
}} = 1;
3264 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
3266 my $q35 = machine_type_is_q35
($conf);
3268 my $devices_list = vm_devices_list
($vmid);
3269 return 1 if defined($devices_list->{$deviceid});
3271 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid); # add PCI bridge if we need it for the device
3273 if ($deviceid eq 'tablet') {
3275 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf));
3277 } elsif ($deviceid =~ m/^usb(\d+)$/) {
3279 die "usb hotplug currently not reliable\n";
3280 # since we can't reliably hot unplug all added usb devices
3281 # and usb passthrough disables live migration
3282 # we disable usb hotplugging for now
3283 qemu_deviceadd
($vmid, PVE
::QemuServer
::USB
::print_usbdevice_full
($conf, $deviceid, $device));
3285 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3287 qemu_iothread_add
($vmid, $deviceid, $device);
3289 qemu_driveadd
($storecfg, $vmid, $device);
3290 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3292 qemu_deviceadd
($vmid, $devicefull);
3293 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3295 eval { qemu_drivedel
($vmid, $deviceid); };
3300 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3303 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
3304 my $pciaddr = print_pci_addr
($deviceid);
3305 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
3307 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
3309 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
3310 qemu_iothread_add
($vmid, $deviceid, $device);
3311 $devicefull .= ",iothread=iothread-$deviceid";
3314 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
3315 $devicefull .= ",num_queues=$device->{queues}";
3318 qemu_deviceadd
($vmid, $devicefull);
3319 qemu_deviceaddverify
($vmid, $deviceid);
3321 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3323 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device);
3324 qemu_driveadd
($storecfg, $vmid, $device);
3326 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3327 eval { qemu_deviceadd
($vmid, $devicefull); };
3329 eval { qemu_drivedel
($vmid, $deviceid); };
3334 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3336 return undef if !qemu_netdevadd
($vmid, $conf, $device, $deviceid);
3338 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
3339 my $use_old_bios_files = undef;
3340 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3342 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files);
3343 qemu_deviceadd
($vmid, $netdevicefull);
3344 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3346 eval { qemu_netdevdel
($vmid, $deviceid); };
3351 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
3354 my $pciaddr = print_pci_addr
($deviceid);
3355 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
3357 qemu_deviceadd
($vmid, $devicefull);
3358 qemu_deviceaddverify
($vmid, $deviceid);
3361 die "can't hotplug device '$deviceid'\n";
3367 # fixme: this should raise exceptions on error!
3368 sub vm_deviceunplug
{
3369 my ($vmid, $conf, $deviceid) = @_;
3371 my $devices_list = vm_devices_list
($vmid);
3372 return 1 if !defined($devices_list->{$deviceid});
3374 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
3376 if ($deviceid eq 'tablet') {
3378 qemu_devicedel
($vmid, $deviceid);
3380 } elsif ($deviceid =~ m/^usb\d+$/) {
3382 die "usb hotplug currently not reliable\n";
3383 # when unplugging usb devices this way,
3384 # there may be remaining usb controllers/hubs
3385 # so we disable it for now
3386 qemu_devicedel
($vmid, $deviceid);
3387 qemu_devicedelverify
($vmid, $deviceid);
3389 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3391 qemu_devicedel
($vmid, $deviceid);
3392 qemu_devicedelverify
($vmid, $deviceid);
3393 qemu_drivedel
($vmid, $deviceid);
3394 qemu_iothread_del
($conf, $vmid, $deviceid);
3396 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3398 qemu_devicedel
($vmid, $deviceid);
3399 qemu_devicedelverify
($vmid, $deviceid);
3400 qemu_iothread_del
($conf, $vmid, $deviceid);
3402 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3404 #qemu 2.3 segfault on drive_del with virtioscsi + iothread
3405 my $device = parse_drive
($deviceid, $conf->{$deviceid});
3406 die "virtioscsi with iothread is not hot-unplugglable currently" if $device->{iothread
};
3408 qemu_devicedel
($vmid, $deviceid);
3409 qemu_drivedel
($vmid, $deviceid);
3410 qemu_deletescsihw
($conf, $vmid, $deviceid);
3412 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3414 qemu_devicedel
($vmid, $deviceid);
3415 qemu_devicedelverify
($vmid, $deviceid);
3416 qemu_netdevdel
($vmid, $deviceid);
3419 die "can't unplug device '$deviceid'\n";
3425 sub qemu_deviceadd
{
3426 my ($vmid, $devicefull) = @_;
3428 $devicefull = "driver=".$devicefull;
3429 my %options = split(/[=,]/, $devicefull);
3431 vm_mon_cmd
($vmid, "device_add" , %options);
3434 sub qemu_devicedel
{
3435 my ($vmid, $deviceid) = @_;
3437 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
3440 sub qemu_iothread_add
{
3441 my($vmid, $deviceid, $device) = @_;
3443 if ($device->{iothread
}) {
3444 my $iothreads = vm_iothreads_list
($vmid);
3445 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
3449 sub qemu_iothread_del
{
3450 my($conf, $vmid, $deviceid) = @_;
3452 my $device = parse_drive
($deviceid, $conf->{$deviceid});
3453 if ($device->{iothread
}) {
3454 my $iothreads = vm_iothreads_list
($vmid);
3455 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
3459 sub qemu_objectadd
{
3460 my($vmid, $objectid, $qomtype) = @_;
3462 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
3467 sub qemu_objectdel
{
3468 my($vmid, $objectid) = @_;
3470 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
3476 my ($storecfg, $vmid, $device) = @_;
3478 my $drive = print_drive_full
($storecfg, $vmid, $device);
3479 $drive =~ s/\\/\\\\/g;
3480 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
3482 # If the command succeeds qemu prints: "OK
"
3483 return 1 if $ret =~ m/OK/s;
3485 die "adding drive failed
: $ret\n";
3489 my($vmid, $deviceid) = @_;
3491 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
3494 return 1 if $ret eq "";
3496 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
3497 return 1 if $ret =~ m/Device \'.*?\' not found/s;
3499 die "deleting drive
$deviceid failed
: $ret\n";
3502 sub qemu_deviceaddverify {
3503 my ($vmid, $deviceid) = @_;
3505 for (my $i = 0; $i <= 5; $i++) {
3506 my $devices_list = vm_devices_list($vmid);
3507 return 1 if defined($devices_list->{$deviceid});
3511 die "error on hotplug device
'$deviceid'\n";
3515 sub qemu_devicedelverify {
3516 my ($vmid, $deviceid) = @_;
3518 # need to verify that the device is correctly removed as device_del
3519 # is async and empty return is not reliable
3521 for (my $i = 0; $i <= 5; $i++) {
3522 my $devices_list = vm_devices_list($vmid);
3523 return 1 if !defined($devices_list->{$deviceid});
3527 die "error on hot-unplugging device
'$deviceid'\n";
3530 sub qemu_findorcreatescsihw {
3531 my ($storecfg, $conf, $vmid, $device) = @_;
3533 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3535 my $scsihwid="$controller_prefix$controller";
3536 my $devices_list = vm_devices_list($vmid);
3538 if(!defined($devices_list->{$scsihwid})) {
3539 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device);
3545 sub qemu_deletescsihw {
3546 my ($conf, $vmid, $opt) = @_;
3548 my $device = parse_drive($opt, $conf->{$opt});
3550 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
3551 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
3555 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3557 my $devices_list = vm_devices_list($vmid);
3558 foreach my $opt (keys %{$devices_list}) {
3559 if (PVE::QemuServer::is_valid_drivename($opt)) {
3560 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
3561 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
3567 my $scsihwid="scsihw
$controller";
3569 vm_deviceunplug($vmid, $conf, $scsihwid);
3574 sub qemu_add_pci_bridge {
3575 my ($storecfg, $conf, $vmid, $device) = @_;
3581 print_pci_addr($device, $bridges);
3583 while (my ($k, $v) = each %$bridges) {
3586 return 1 if !defined($bridgeid) || $bridgeid < 1;
3588 my $bridge = "pci
.$bridgeid";
3589 my $devices_list = vm_devices_list($vmid);
3591 if (!defined($devices_list->{$bridge})) {
3592 vm_deviceplug($storecfg, $conf, $vmid, $bridge);
3598 sub qemu_set_link_status {
3599 my ($vmid, $device, $up) = @_;
3601 vm_mon_cmd($vmid, "set_link
", name => $device,
3602 up => $up ? JSON::true : JSON::false);
3605 sub qemu_netdevadd {
3606 my ($vmid, $conf, $device, $deviceid) = @_;
3608 my $netdev = print_netdev_full($vmid, $conf, $device, $deviceid, 1);
3609 my %options = split(/[=,]/, $netdev);
3611 vm_mon_cmd($vmid, "netdev_add
", %options);
3615 sub qemu_netdevdel {
3616 my ($vmid, $deviceid) = @_;
3618 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
3621 sub qemu_usb_hotplug {
3622 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
3626 # remove the old one first
3627 vm_deviceunplug($vmid, $conf, $deviceid);
3629 # check if xhci controller is necessary and available
3630 if ($device->{usb3}) {
3632 my $devicelist = vm_devices_list($vmid);
3634 if (!$devicelist->{xhci}) {
3635 my $pciaddr = print_pci_addr("xhci
");
3636 qemu_deviceadd($vmid, "nec-usb-xhci
,id
=xhci
$pciaddr");
3639 my $d = parse_usb_device($device->{host});
3640 $d->{usb3} = $device->{usb3};
3643 vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d);
3646 sub qemu_cpu_hotplug {
3647 my ($vmid, $conf, $vcpus) = @_;
3650 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
3651 $sockets = $conf->{sockets} if $conf->{sockets};
3652 my $cores = $conf->{cores} || 1;
3653 my $maxcpus = $sockets * $cores;
3655 $vcpus = $maxcpus if !$vcpus;
3657 die "you can
't add more vcpus than maxcpus\n"
3658 if $vcpus > $maxcpus;
3660 my $currentvcpus = $conf->{vcpus} || $maxcpus;
3661 die "online cpu unplug is not yet possible\n"
3662 if $vcpus < $currentvcpus;
3664 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
3665 die "vcpus in running vm is different than configuration\n"
3666 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
3668 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
3669 vm_mon_cmd($vmid, "cpu-add", id => int($i));
3673 sub qemu_block_set_io_throttle {
3674 my ($vmid, $deviceid,
3675 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
3676 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max) = @_;
3678 return if !check_running($vmid) ;
3680 vm_mon_cmd($vmid, "block_set_io_throttle", device => $deviceid,
3682 bps_rd => int($bps_rd),
3683 bps_wr => int($bps_wr),
3685 iops_rd => int($iops_rd),
3686 iops_wr => int($iops_wr),
3687 bps_max => int($bps_max),
3688 bps_rd_max => int($bps_rd_max),
3689 bps_wr_max => int($bps_wr_max),
3690 iops_max => int($iops_max),
3691 iops_rd_max => int($iops_rd_max),
3692 iops_wr_max => int($iops_wr_max)
3697 # old code, only used to shutdown old VM after update
3699 my ($fh, $timeout) = @_;
3701 my $sel = new IO::Select;
3708 while (scalar (@ready = $sel->can_read($timeout))) {
3710 if ($count = $fh->sysread($buf, 8192)) {
3711 if ($buf =~ /^(.*)\(qemu\) $/s) {
3718 if (!defined($count)) {
3725 die "monitor read timeout\n" if !scalar(@ready);
3730 # old code, only used to shutdown old VM after update
3731 sub vm_monitor_command {
3732 my ($vmid, $cmdstr, $nocheck) = @_;
3737 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
3739 my $sname = "${var_run_tmpdir}/$vmid.mon";
3741 my $sock = IO::Socket::UNIX->new( Peer => $sname ) ||
3742 die "unable to connect to VM $vmid socket - $!\n";
3746 # hack: migrate sometime blocks the monitor (when migrate_downtime
3748 if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
3749 $timeout = 60*60; # 1 hour
3753 my $data = __read_avail($sock, $timeout);
3755 if ($data !~ m/^QEMU\s+(\S+)\s+monitor\s/) {
3756 die "got unexpected qemu monitor banner\n";
3759 my $sel = new IO::Select;
3762 if (!scalar(my @ready = $sel->can_write($timeout))) {
3763 die "monitor write error - timeout";
3766 my $fullcmd = "$cmdstr\r";
3768 # syslog('info
', "VM $vmid monitor command: $cmdstr");
3771 if (!($b = $sock->syswrite($fullcmd)) || ($b != length($fullcmd))) {
3772 die "monitor write error - $!";
3775 return if ($cmdstr eq 'q
') || ($cmdstr eq 'quit
');
3779 if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
3780 $timeout = 60*60; # 1 hour
3781 } elsif ($cmdstr =~ m/^(eject|change)/) {
3782 $timeout = 60; # note: cdrom mount command is slow
3784 if ($res = __read_avail($sock, $timeout)) {
3786 my @lines = split("\r?\n", $res);
3788 shift @lines if $lines[0] !~ m/^unknown command/; # skip echo
3790 $res = join("\n", @lines);
3798 syslog("err", "VM $vmid monitor command failed - $err");
3805 sub qemu_block_resize {
3806 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
3808 my $running = check_running($vmid);
3810 return if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
3812 return if !$running;
3814 vm_mon_cmd($vmid, "block_resize", device => $deviceid, size => int($size));
3818 sub qemu_volume_snapshot {
3819 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
3821 my $running = check_running($vmid);
3823 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
3824 vm_mon_cmd($vmid, "snapshot-drive", device => $deviceid, name => $snap);
3826 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
3830 sub qemu_volume_snapshot_delete {
3831 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
3833 my $running = check_running($vmid);
3835 return if !PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
3837 return if !$running;
3839 vm_mon_cmd($vmid, "delete-drive-snapshot", device => $deviceid, name => $snap);
3842 sub set_migration_caps {
3848 "auto-converge" => 1,
3850 "x-rdma-pin-all" => 0,
3855 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities");
3857 for my $supported_capability (@$supported_capabilities) {
3859 capability => $supported_capability->{capability},
3860 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
3864 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities", capabilities => $cap_ref);
3867 my $fast_plug_option = {
3876 # hotplug changes in [PENDING]
3877 # $selection hash can be used to only apply specified options, for
3878 # example: { cores => 1 } (only apply changed 'cores
')
3879 # $errors ref is used to return error messages
3880 sub vmconfig_hotplug_pending {
3881 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
3883 my $defaults = load_defaults();
3885 # commit values which do not have any impact on running VM first
3886 # Note: those option cannot raise errors, we we do not care about
3887 # $selection and always apply them.
3889 my $add_error = sub {
3890 my ($opt, $msg) = @_;
3891 $errors->{$opt} = "hotplug problem - $msg";
3895 foreach my $opt (keys %{$conf->{pending}}) { # add/change
3896 if ($fast_plug_option->{$opt}) {
3897 $conf->{$opt} = $conf->{pending}->{$opt};
3898 delete $conf->{pending}->{$opt};
3904 PVE::QemuConfig->write_config($vmid, $conf);
3905 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
3908 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
3910 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
3911 while (my ($opt, $force) = each %$pending_delete_hash) {
3912 next if $selection && !$selection->{$opt};
3914 if ($opt eq 'hotplug
') {
3915 die "skip\n" if ($conf->{hotplug} =~ /memory/);
3916 } elsif ($opt eq 'tablet
') {
3917 die "skip\n" if !$hotplug_features->{usb};
3918 if ($defaults->{tablet}) {
3919 vm_deviceplug($storecfg, $conf, $vmid, $opt);
3921 vm_deviceunplug($vmid, $conf, $opt);
3923 } elsif ($opt =~ m/^usb\d+/) {
3925 # since we cannot reliably hot unplug usb devices
3926 # we are disabling it
3927 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
3928 vm_deviceunplug($vmid, $conf, $opt);
3929 } elsif ($opt eq 'vcpus
') {
3930 die "skip\n" if !$hotplug_features->{cpu};
3931 qemu_cpu_hotplug($vmid, $conf, undef);
3932 } elsif ($opt eq 'balloon
') {
3933 # enable balloon device is not hotpluggable
3934 die "skip\n" if !defined($conf->{balloon}) || $conf->{balloon};
3935 } elsif ($fast_plug_option->{$opt}) {
3937 } elsif ($opt =~ m/^net(\d+)$/) {
3938 die "skip\n" if !$hotplug_features->{network};
3939 vm_deviceunplug($vmid, $conf, $opt);
3940 } elsif (is_valid_drivename($opt)) {
3941 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
3942 vm_deviceunplug($vmid, $conf, $opt);
3943 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
3944 } elsif ($opt =~ m/^memory$/) {
3945 die "skip\n" if !$hotplug_features->{memory};
3946 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
3947 } elsif ($opt eq 'cpuunits
') {
3948 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
3949 } elsif ($opt eq 'cpulimit
') {
3950 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
3956 &$add_error($opt, $err) if $err ne "skip\n";
3958 # save new config if hotplug was successful
3959 delete $conf->{$opt};
3960 vmconfig_undelete_pending_option($conf, $opt);
3961 PVE::QemuConfig->write_config($vmid, $conf);
3962 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
3966 foreach my $opt (keys %{$conf->{pending}}) {
3967 next if $selection && !$selection->{$opt};
3968 my $value = $conf->{pending}->{$opt};
3970 if ($opt eq 'hotplug
') {
3971 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
3972 } elsif ($opt eq 'tablet
') {
3973 die "skip\n" if !$hotplug_features->{usb};
3975 vm_deviceplug($storecfg, $conf, $vmid, $opt);
3976 } elsif ($value == 0) {
3977 vm_deviceunplug($vmid, $conf, $opt);
3979 } elsif ($opt =~ m/^usb\d+$/) {
3981 # since we cannot reliably hot unplug usb devices
3982 # we are disabling it
3983 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
3984 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
3985 die "skip\n" if !$d;
3986 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d);
3987 } elsif ($opt eq 'vcpus
') {
3988 die "skip\n" if !$hotplug_features->{cpu};
3989 qemu_cpu_hotplug($vmid, $conf, $value);
3990 } elsif ($opt eq 'balloon
') {
3991 # enable/disable balloning device is not hotpluggable
3992 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
3993 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
3994 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
3996 # allow manual ballooning if shares is set to zero
3997 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
3998 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
3999 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4001 } elsif ($opt =~ m/^net(\d+)$/) {
4002 # some changes can be done without hotplug
4003 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4004 $vmid, $opt, $value);
4005 } elsif (is_valid_drivename($opt)) {
4006 # some changes can be done without hotplug
4007 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4008 $vmid, $opt, $value, 1);
4009 } elsif ($opt =~ m/^memory$/) { #dimms
4010 die "skip\n" if !$hotplug_features->{memory};
4011 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4012 } elsif ($opt eq 'cpuunits
') {
4013 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4014 } elsif ($opt eq 'cpulimit
') {
4015 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4016 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4018 die "skip\n"; # skip non-hot-pluggable options
4022 &$add_error($opt, $err) if $err ne "skip\n";
4024 # save new config if hotplug was successful
4025 $conf->{$opt} = $value;
4026 delete $conf->{pending}->{$opt};
4027 PVE::QemuConfig->write_config($vmid, $conf);
4028 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4033 sub try_deallocate_drive {
4034 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4036 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4037 my $volid = $drive->{file};
4038 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4039 my $sid = PVE::Storage::parse_volume_id($volid);
4040 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4042 # check if the disk is really unused
4043 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4044 if is_volume_in_use($storecfg, $conf, $key, $volid);
4045 PVE::Storage::vdisk_free($storecfg, $volid);
4048 # If vm is not owner of this disk remove from config
4056 sub vmconfig_delete_or_detach_drive {
4057 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4059 my $drive = parse_drive($opt, $conf->{$opt});
4061 my $rpcenv = PVE::RPCEnvironment::get();
4062 my $authuser = $rpcenv->get_user();
4065 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4066 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4068 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4072 sub vmconfig_apply_pending {
4073 my ($vmid, $conf, $storecfg) = @_;
4077 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4078 while (my ($opt, $force) = each %$pending_delete_hash) {
4079 die "internal error" if $opt =~ m/^unused/;
4080 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4081 if (!defined($conf->{$opt})) {
4082 vmconfig_undelete_pending_option($conf, $opt);
4083 PVE::QemuConfig->write_config($vmid, $conf);
4084 } elsif (is_valid_drivename($opt)) {
4085 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4086 vmconfig_undelete_pending_option($conf, $opt);
4087 delete $conf->{$opt};
4088 PVE::QemuConfig->write_config($vmid, $conf);
4090 vmconfig_undelete_pending_option($conf, $opt);
4091 delete $conf->{$opt};
4092 PVE::QemuConfig->write_config($vmid, $conf);
4096 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4098 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4099 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4101 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4102 # skip if nothing changed
4103 } elsif (is_valid_drivename($opt)) {
4104 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4105 if defined($conf->{$opt});
4106 $conf->{$opt} = $conf->{pending}->{$opt};
4108 $conf->{$opt} = $conf->{pending}->{$opt};
4111 delete $conf->{pending}->{$opt};
4112 PVE::QemuConfig->write_config($vmid, $conf);
4116 my $safe_num_ne = sub {
4119 return 0 if !defined($a) && !defined($b);
4120 return 1 if !defined($a);
4121 return 1 if !defined($b);
4126 my $safe_string_ne = sub {
4129 return 0 if !defined($a) && !defined($b);
4130 return 1 if !defined($a);
4131 return 1 if !defined($b);
4136 sub vmconfig_update_net {
4137 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value) = @_;
4139 my $newnet = parse_net($value);
4141 if ($conf->{$opt}) {
4142 my $oldnet = parse_net($conf->{$opt});
4144 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4145 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4146 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4147 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4149 # for non online change, we try to hot-unplug
4150 die "skip\n" if !$hotplug;
4151 vm_deviceunplug($vmid, $conf, $opt);
4154 die "internal error" if $opt !~ m/net(\d+)/;
4155 my $iface = "tap${vmid}i$1";
4157 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4158 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4159 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4160 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4161 PVE::Network::tap_unplug($iface);
4162 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4163 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4164 # Rate can be applied on its own but any change above needs to
4165 # include the rate in tap_plug since OVS resets everything.
4166 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4169 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4170 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4178 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet);
4184 sub vmconfig_update_disk {
4185 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force) = @_;
4187 # fixme: do we need force?
4189 my $drive = parse_drive($opt, $value);
4191 if ($conf->{$opt}) {
4193 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4195 my $media = $drive->{media} || 'disk
';
4196 my $oldmedia = $old_drive->{media} || 'disk
';
4197 die "unable to change media type\n" if $media ne $oldmedia;
4199 if (!drive_is_cdrom($old_drive)) {
4201 if ($drive->{file} ne $old_drive->{file}) {
4203 die "skip\n" if !$hotplug;
4205 # unplug and register as unused
4206 vm_deviceunplug($vmid, $conf, $opt);
4207 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4210 # update existing disk
4212 # skip non hotpluggable value
4213 if (&$safe_num_ne($drive->{discard}, $old_drive->{discard}) ||
4214 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4215 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4216 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
4221 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4222 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4223 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4224 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4225 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4226 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4227 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4228 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4229 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4230 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4231 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4232 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max})) {
4234 qemu_block_set_io_throttle($vmid,"drive-$opt",
4235 ($drive->{mbps} || 0)*1024*1024,
4236 ($drive->{mbps_rd} || 0)*1024*1024,
4237 ($drive->{mbps_wr} || 0)*1024*1024,
4238 $drive->{iops} || 0,
4239 $drive->{iops_rd} || 0,
4240 $drive->{iops_wr} || 0,
4241 ($drive->{mbps_max} || 0)*1024*1024,
4242 ($drive->{mbps_rd_max} || 0)*1024*1024,
4243 ($drive->{mbps_wr_max} || 0)*1024*1024,
4244 $drive->{iops_max} || 0,
4245 $drive->{iops_rd_max} || 0,
4246 $drive->{iops_wr_max} || 0);
4255 if ($drive->{file} eq 'none
') {
4256 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
4258 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4259 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
4260 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
4268 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4270 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
4271 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive);
4275 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
4276 $forcemachine, $spice_ticket) = @_;
4278 PVE::QemuConfig->lock_config($vmid, sub {
4279 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
4281 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
4283 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4285 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
4287 if (!$statefile && scalar(keys %{$conf->{pending}})) {
4288 vmconfig_apply_pending($vmid, $conf, $storecfg);
4289 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4292 my $defaults = load_defaults();
4294 # set environment variable useful inside network script
4295 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
4297 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
4299 my $migrate_port = 0;
4302 if ($statefile eq 'tcp
') {
4303 my $localip = "localhost";
4304 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
4305 my $nodename = PVE::INotify::nodename();
4306 if ($datacenterconf->{migration_unsecure}) {
4307 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
4308 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4310 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4311 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4312 $migrate_uri = "tcp:${localip}:${migrate_port}";
4313 push @$cmd, '-incoming
', $migrate_uri;
4316 } elsif ($statefile eq 'unix
') {
4317 # should be default for secure migrations as a ssh TCP forward
4318 # tunnel is not deterministic reliable ready and fails regurarly
4319 # to set up in time, so use UNIX socket forwards
4320 my $socket_addr = "/run/qemu-server/$vmid.migrate";
4321 unlink $socket_addr;
4323 $migrate_uri = "unix:$socket_addr";
4325 push @$cmd, '-incoming
', $migrate_uri;
4329 push @$cmd, '-loadstate
', $statefile;
4336 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
4337 my $d = parse_hostpci($conf->{"hostpci$i"});
4339 my $pcidevices = $d->{pciid};
4340 foreach my $pcidevice (@$pcidevices) {
4341 my $pciid = $pcidevice->{id}.".".$pcidevice->{function};
4343 my $info = pci_device_info("0000:$pciid");
4344 die "IOMMU not present\n" if !check_iommu_support();
4345 die "no pci device info for device '$pciid'\n" if !$info;
4346 die "can't unbind
/bind pci group to vfio
'$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
4347 die "can
't reset pci device '$pciid'\n" if $info->{has_fl_reset} and !pci_dev_reset($info);
4351 PVE::Storage::activate_volumes($storecfg, $vollist);
4353 if (!check_running($vmid, 1) && -d "/sys/fs/cgroup/systemd/qemu.slice/$vmid.scope") {
4355 push @$cmd, '/bin/systemctl
', 'stop
', "$vmid.scope";
4356 eval { run_command($cmd); };
4359 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
4360 : $defaults->{cpuunits};
4362 my %run_params = (timeout => $statefile ? undef : 30, umask => 0077);
4365 Slice => 'qemu
.slice
',
4367 CPUShares => $cpuunits
4370 if (my $cpulimit = $conf->{cpulimit}) {
4371 $properties{CPUQuota} = int($cpulimit * 100);
4373 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
4375 if ($conf->{hugepages}) {
4378 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
4379 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
4381 PVE::QemuServer::Memory::hugepages_mount();
4382 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
4385 PVE::Tools::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4386 run_command($cmd, %run_params);
4390 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
4394 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
4396 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
4400 PVE::Tools::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4401 run_command($cmd, %run_params);
4406 # deactivate volumes if start fails
4407 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
4408 die "start failed: $err";
4411 print "migration listens on $migrate_uri\n" if $migrate_uri;
4413 if ($statefile && $statefile ne 'tcp
') {
4414 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
4418 if ($migratedfrom) {
4421 set_migration_caps($vmid);
4426 print "spice listens on port $spice_port\n";
4427 if ($spice_ticket) {
4428 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
4429 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
4435 if (!$statefile && (!defined($conf->{balloon}) || $conf->{balloon})) {
4436 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
4437 if $conf->{balloon};
4440 foreach my $opt (keys %$conf) {
4441 next if $opt !~ m/^net\d+$/;
4442 my $nicconf = parse_net($conf->{$opt});
4443 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
4447 vm_mon_cmd_nocheck($vmid, 'qom-set
',
4448 path => "machine/peripheral/balloon0",
4449 property => "guest-stats-polling-interval",
4450 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
4456 my ($vmid, $execute, %params) = @_;
4458 my $cmd = { execute => $execute, arguments => \%params };
4459 vm_qmp_command($vmid, $cmd);
4462 sub vm_mon_cmd_nocheck {
4463 my ($vmid, $execute, %params) = @_;
4465 my $cmd = { execute => $execute, arguments => \%params };
4466 vm_qmp_command($vmid, $cmd, 1);
4469 sub vm_qmp_command {
4470 my ($vmid, $cmd, $nocheck) = @_;
4475 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
4476 $timeout = $cmd->{arguments}->{timeout};
4477 delete $cmd->{arguments}->{timeout};
4481 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
4482 my $sname = qmp_socket($vmid);
4483 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
4484 my $qmpclient = PVE::QMPClient->new();
4486 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
4487 } elsif (-e "${var_run_tmpdir}/$vmid.mon") {
4488 die "can't execute complex command on old monitor
- stop
/start your vm to fix the problem
\n"
4489 if scalar(%{$cmd->{arguments}});
4490 vm_monitor_command($vmid, $cmd->{execute}, $nocheck);
4492 die "unable to
open monitor
socket\n";
4496 syslog("err
", "VM
$vmid qmp command failed
- $err");
4503 sub vm_human_monitor_command {
4504 my ($vmid, $cmdline) = @_;
4509 execute => 'human-monitor-command',
4510 arguments => { 'command-line' => $cmdline},
4513 return vm_qmp_command($vmid, $cmd);
4516 sub vm_commandline {
4517 my ($storecfg, $vmid) = @_;
4519 my $conf = PVE::QemuConfig->load_config($vmid);
4521 my $defaults = load_defaults();
4523 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
4525 return join(' ', @$cmd);
4529 my ($vmid, $skiplock) = @_;
4531 PVE::QemuConfig->lock_config($vmid, sub {
4533 my $conf = PVE::QemuConfig->load_config($vmid);
4535 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4537 vm_mon_cmd($vmid, "system_reset
");
4541 sub get_vm_volumes {
4545 foreach_volid($conf, sub {
4546 my ($volid, $is_cdrom) = @_;
4548 return if $volid =~ m|^/|;
4550 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
4553 push @$vollist, $volid;
4559 sub vm_stop_cleanup {
4560 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
4565 my $vollist = get_vm_volumes($conf);
4566 PVE::Storage::deactivate_volumes($storecfg, $vollist);
4569 foreach my $ext (qw(mon qmp pid vnc qga)) {
4570 unlink "/var/run/qemu-server/${vmid}.$ext";
4573 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
4575 warn $@ if $@; # avoid errors - just warn
4578 # Note: use $nockeck to skip tests if VM configuration file exists.
4579 # We need that when migration VMs to other nodes (files already moved)
4580 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
4582 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
4584 $force = 1 if !defined($force) && !$shutdown;
4587 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
4588 kill 15, $pid if $pid;
4589 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
4590 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
4594 PVE
::QemuConfig-
>lock_config($vmid, sub {
4596 my $pid = check_running
($vmid, $nocheck);
4601 $conf = PVE
::QemuConfig-
>load_config($vmid);
4602 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
4603 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
4604 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
4605 $timeout = $opts->{down
} if $opts->{down
};
4609 $timeout = 60 if !defined($timeout);
4613 if (defined($conf) && $conf->{agent
}) {
4614 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
4616 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
4619 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
4626 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
4631 if ($count >= $timeout) {
4633 warn "VM still running - terminating now with SIGTERM\n";
4636 die "VM quit/powerdown failed - got timeout\n";
4639 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
4644 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
4647 die "VM quit/powerdown failed\n";
4655 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
4660 if ($count >= $timeout) {
4661 warn "VM still running - terminating now with SIGKILL\n";
4666 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
4671 my ($vmid, $skiplock) = @_;
4673 PVE
::QemuConfig-
>lock_config($vmid, sub {
4675 my $conf = PVE
::QemuConfig-
>load_config($vmid);
4677 PVE
::QemuConfig-
>check_lock($conf)
4678 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
4680 vm_mon_cmd
($vmid, "stop");
4685 my ($vmid, $skiplock, $nocheck) = @_;
4687 PVE
::QemuConfig-
>lock_config($vmid, sub {
4691 my $conf = PVE
::QemuConfig-
>load_config($vmid);
4693 PVE
::QemuConfig-
>check_lock($conf)
4694 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
4696 vm_mon_cmd
($vmid, "cont");
4699 vm_mon_cmd_nocheck
($vmid, "cont");
4705 my ($vmid, $skiplock, $key) = @_;
4707 PVE
::QemuConfig-
>lock_config($vmid, sub {
4709 my $conf = PVE
::QemuConfig-
>load_config($vmid);
4711 # there is no qmp command, so we use the human monitor command
4712 vm_human_monitor_command
($vmid, "sendkey $key");
4717 my ($storecfg, $vmid, $skiplock) = @_;
4719 PVE
::QemuConfig-
>lock_config($vmid, sub {
4721 my $conf = PVE
::QemuConfig-
>load_config($vmid);
4723 if (!check_running
($vmid)) {
4724 destroy_vm
($storecfg, $vmid, undef, $skiplock);
4726 die "VM $vmid is running - destroy failed\n";
4734 my ($filename, $buf) = @_;
4736 my $fh = IO
::File-
>new($filename, "w");
4737 return undef if !$fh;
4739 my $res = print $fh $buf;
4746 sub pci_device_info
{
4751 return undef if $name !~ m/^([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\.([a-f0-9])$/;
4752 my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4);
4754 my $irq = file_read_firstline
("$pcisysfs/devices/$name/irq");
4755 return undef if !defined($irq) || $irq !~ m/^\d+$/;
4757 my $vendor = file_read_firstline
("$pcisysfs/devices/$name/vendor");
4758 return undef if !defined($vendor) || $vendor !~ s/^0x//;
4760 my $product = file_read_firstline
("$pcisysfs/devices/$name/device");
4761 return undef if !defined($product) || $product !~ s/^0x//;
4766 product
=> $product,
4772 has_fl_reset
=> -f
"$pcisysfs/devices/$name/reset" || 0,
4781 my $name = $dev->{name
};
4783 my $fn = "$pcisysfs/devices/$name/reset";
4785 return file_write
($fn, "1");
4788 sub pci_dev_bind_to_vfio
{
4791 my $name = $dev->{name
};
4793 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
4795 if (!-d
$vfio_basedir) {
4796 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
4798 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
4800 my $testdir = "$vfio_basedir/$name";
4801 return 1 if -d
$testdir;
4803 my $data = "$dev->{vendor} $dev->{product}";
4804 return undef if !file_write
("$vfio_basedir/new_id", $data);
4806 my $fn = "$pcisysfs/devices/$name/driver/unbind";
4807 if (!file_write
($fn, $name)) {
4808 return undef if -f
$fn;
4811 $fn = "$vfio_basedir/bind";
4812 if (! -d
$testdir) {
4813 return undef if !file_write
($fn, $name);
4819 sub pci_dev_group_bind_to_vfio
{
4822 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
4824 if (!-d
$vfio_basedir) {
4825 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
4827 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
4829 # get IOMMU group devices
4830 opendir(my $D, "$pcisysfs/devices/0000:$pciid/iommu_group/devices/") || die "Cannot open iommu_group: $!\n";
4831 my @devs = grep /^0000:/, readdir($D);
4834 foreach my $pciid (@devs) {
4835 $pciid =~ m/^([:\.\da-f]+)$/ or die "PCI ID $pciid not valid!\n";
4837 # pci bridges, switches or root ports are not supported
4838 # they have a pci_bus subdirectory so skip them
4839 next if (-e
"$pcisysfs/devices/$pciid/pci_bus");
4841 my $info = pci_device_info
($1);
4842 pci_dev_bind_to_vfio
($info) || die "Cannot bind $pciid to vfio\n";
4848 # vzdump restore implementaion
4850 sub tar_archive_read_firstfile
{
4851 my $archive = shift;
4853 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
4855 # try to detect archive type first
4856 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
4857 die "unable to open file '$archive'\n";
4858 my $firstfile = <$fh>;
4862 die "ERROR: archive contaions no data\n" if !$firstfile;
4868 sub tar_restore_cleanup
{
4869 my ($storecfg, $statfile) = @_;
4871 print STDERR
"starting cleanup\n";
4873 if (my $fd = IO
::File-
>new($statfile, "r")) {
4874 while (defined(my $line = <$fd>)) {
4875 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
4878 if ($volid =~ m
|^/|) {
4879 unlink $volid || die 'unlink failed\n';
4881 PVE
::Storage
::vdisk_free
($storecfg, $volid);
4883 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
4885 print STDERR
"unable to cleanup '$volid' - $@" if $@;
4887 print STDERR
"unable to parse line in statfile - $line";
4894 sub restore_archive
{
4895 my ($archive, $vmid, $user, $opts) = @_;
4897 my $format = $opts->{format
};
4900 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
4901 $format = 'tar' if !$format;
4903 } elsif ($archive =~ m/\.tar$/) {
4904 $format = 'tar' if !$format;
4905 } elsif ($archive =~ m/.tar.lzo$/) {
4906 $format = 'tar' if !$format;
4908 } elsif ($archive =~ m/\.vma$/) {
4909 $format = 'vma' if !$format;
4910 } elsif ($archive =~ m/\.vma\.gz$/) {
4911 $format = 'vma' if !$format;
4913 } elsif ($archive =~ m/\.vma\.lzo$/) {
4914 $format = 'vma' if !$format;
4917 $format = 'vma' if !$format; # default
4920 # try to detect archive format
4921 if ($format eq 'tar') {
4922 return restore_tar_archive
($archive, $vmid, $user, $opts);
4924 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
4928 sub restore_update_config_line
{
4929 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
4931 return if $line =~ m/^\#qmdump\#/;
4932 return if $line =~ m/^\#vzdump\#/;
4933 return if $line =~ m/^lock:/;
4934 return if $line =~ m/^unused\d+:/;
4935 return if $line =~ m/^parent:/;
4936 return if $line =~ m/^template:/; # restored VM is never a template
4938 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
4939 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
4940 # try to convert old 1.X settings
4941 my ($id, $ind, $ethcfg) = ($1, $2, $3);
4942 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
4943 my ($model, $macaddr) = split(/\=/, $devconfig);
4944 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
4947 bridge
=> "vmbr$ind",
4948 macaddr
=> $macaddr,
4950 my $netstr = print_net
($net);
4952 print $outfd "net$cookie->{netcount}: $netstr\n";
4953 $cookie->{netcount
}++;
4955 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
4956 my ($id, $netstr) = ($1, $2);
4957 my $net = parse_net
($netstr);
4958 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
4959 $netstr = print_net
($net);
4960 print $outfd "$id: $netstr\n";
4961 } elsif ($line =~ m/^((ide|scsi|virtio|sata)\d+):\s*(\S+)\s*$/) {
4964 my $di = parse_drive
($virtdev, $value);
4965 if (defined($di->{backup
}) && !$di->{backup
}) {
4966 print $outfd "#$line";
4967 } elsif ($map->{$virtdev}) {
4968 delete $di->{format
}; # format can change on restore
4969 $di->{file
} = $map->{$virtdev};
4970 $value = print_drive
($vmid, $di);
4971 print $outfd "$virtdev: $value\n";
4981 my ($cfg, $vmid) = @_;
4983 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
4985 my $volid_hash = {};
4986 foreach my $storeid (keys %$info) {
4987 foreach my $item (@{$info->{$storeid}}) {
4988 next if !($item->{volid
} && $item->{size
});
4989 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
4990 $volid_hash->{$item->{volid
}} = $item;
4997 sub is_volume_in_use
{
4998 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5000 my $path = PVE
::Storage
::path
($storecfg, $volid);
5002 my $scan_config = sub {
5003 my ($cref, $snapname) = @_;
5005 foreach my $key (keys %$cref) {
5006 my $value = $cref->{$key};
5007 if (is_valid_drivename
($key)) {
5008 next if $skip_drive && $key eq $skip_drive;
5009 my $drive = parse_drive
($key, $value);
5010 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5011 return 1 if $volid eq $drive->{file
};
5012 if ($drive->{file
} =~ m!^/!) {
5013 return 1 if $drive->{file
} eq $path;
5015 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5017 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5019 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5027 return 1 if &$scan_config($conf);
5031 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5032 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5038 sub update_disksize
{
5039 my ($vmid, $conf, $volid_hash) = @_;
5045 # Note: it is allowed to define multiple storages with same path (alias), so
5046 # we need to check both 'volid' and real 'path' (two different volid can point
5047 # to the same path).
5052 foreach my $opt (keys %$conf) {
5053 if (is_valid_drivename
($opt)) {
5054 my $drive = parse_drive
($opt, $conf->{$opt});
5055 my $volid = $drive->{file
};
5058 $used->{$volid} = 1;
5059 if ($volid_hash->{$volid} &&
5060 (my $path = $volid_hash->{$volid}->{path
})) {
5061 $usedpath->{$path} = 1;
5064 next if drive_is_cdrom
($drive);
5065 next if !$volid_hash->{$volid};
5067 $drive->{size
} = $volid_hash->{$volid}->{size
};
5068 my $new = print_drive
($vmid, $drive);
5069 if ($new ne $conf->{$opt}) {
5071 $conf->{$opt} = $new;
5076 # remove 'unusedX' entry if volume is used
5077 foreach my $opt (keys %$conf) {
5078 next if $opt !~ m/^unused\d+$/;
5079 my $volid = $conf->{$opt};
5080 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5081 if ($used->{$volid} || ($path && $usedpath->{$path})) {
5083 delete $conf->{$opt};
5087 foreach my $volid (sort keys %$volid_hash) {
5088 next if $volid =~ m/vm-$vmid-state-/;
5089 next if $used->{$volid};
5090 my $path = $volid_hash->{$volid}->{path
};
5091 next if !$path; # just to be sure
5092 next if $usedpath->{$path};
5094 PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5095 $usedpath->{$path} = 1; # avoid to add more than once (aliases)
5102 my ($vmid, $nolock) = @_;
5104 my $cfg = PVE
::Storage
::config
();
5106 my $volid_hash = scan_volids
($cfg, $vmid);
5108 my $updatefn = sub {
5111 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5113 PVE
::QemuConfig-
>check_lock($conf);
5116 foreach my $volid (keys %$volid_hash) {
5117 my $info = $volid_hash->{$volid};
5118 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5121 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5123 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes;
5126 if (defined($vmid)) {
5130 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5133 my $vmlist = config_list
();
5134 foreach my $vmid (keys %$vmlist) {
5138 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5144 sub restore_vma_archive
{
5145 my ($archive, $vmid, $user, $opts, $comp) = @_;
5147 my $input = $archive eq '-' ?
"<&STDIN" : undef;
5148 my $readfrom = $archive;
5153 my $qarchive = PVE
::Tools
::shellquote
($archive);
5154 if ($comp eq 'gzip') {
5155 $uncomp = "zcat $qarchive|";
5156 } elsif ($comp eq 'lzop') {
5157 $uncomp = "lzop -d -c $qarchive|";
5159 die "unknown compression method '$comp'\n";
5164 my $tmpdir = "/var/tmp/vzdumptmp$$";
5167 # disable interrupts (always do cleanups)
5168 local $SIG{INT
} = $SIG{TERM
} = $SIG{QUIT
} = $SIG{HUP
} = sub {
5169 warn "got interrupt - ignored\n";
5172 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
5173 POSIX
::mkfifo
($mapfifo, 0600);
5176 my $openfifo = sub {
5177 open($fifofh, '>', $mapfifo) || die $!;
5180 my $cmd = "${uncomp}vma extract -v -r $mapfifo $readfrom $tmpdir";
5187 my $rpcenv = PVE
::RPCEnvironment
::get
();
5189 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5190 my $tmpfn = "$conffile.$$.tmp";
5192 # Note: $oldconf is undef if VM does not exists
5193 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
5194 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
5196 my $print_devmap = sub {
5197 my $virtdev_hash = {};
5199 my $cfgfn = "$tmpdir/qemu-server.conf";
5201 # we can read the config - that is already extracted
5202 my $fh = IO
::File-
>new($cfgfn, "r") ||
5203 "unable to read qemu-server.conf - $!\n";
5205 my $fwcfgfn = "$tmpdir/qemu-server.fw";
5207 my $pve_firewall_dir = '/etc/pve/firewall';
5208 mkdir $pve_firewall_dir; # make sure the dir exists
5209 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
5212 while (defined(my $line = <$fh>)) {
5213 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
5214 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
5215 die "archive does not contain data for drive '$virtdev'\n"
5216 if !$devinfo->{$devname};
5217 if (defined($opts->{storage
})) {
5218 $storeid = $opts->{storage
} || 'local';
5219 } elsif (!$storeid) {
5222 $format = 'raw' if !$format;
5223 $devinfo->{$devname}->{devname
} = $devname;
5224 $devinfo->{$devname}->{virtdev
} = $virtdev;
5225 $devinfo->{$devname}->{format
} = $format;
5226 $devinfo->{$devname}->{storeid
} = $storeid;
5228 # check permission on storage
5229 my $pool = $opts->{pool
}; # todo: do we need that?
5230 if ($user ne 'root@pam') {
5231 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
5234 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
5238 foreach my $devname (keys %$devinfo) {
5239 die "found no device mapping information for device '$devname'\n"
5240 if !$devinfo->{$devname}->{virtdev
};
5243 my $cfg = PVE
::Storage
::config
();
5245 # create empty/temp config
5247 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
5248 foreach_drive
($oldconf, sub {
5249 my ($ds, $drive) = @_;
5251 return if drive_is_cdrom
($drive);
5253 my $volid = $drive->{file
};
5255 return if !$volid || $volid =~ m
|^/|;
5257 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
5258 return if !$path || !$owner || ($owner != $vmid);
5260 # Note: only delete disk we want to restore
5261 # other volumes will become unused
5262 if ($virtdev_hash->{$ds}) {
5263 PVE
::Storage
::vdisk_free
($cfg, $volid);
5267 # delete vmstate files
5268 # since after the restore we have no snapshots anymore
5269 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
5270 my $snap = $oldconf->{snapshots
}->{$snapname};
5271 if ($snap->{vmstate
}) {
5272 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
5281 foreach my $virtdev (sort keys %$virtdev_hash) {
5282 my $d = $virtdev_hash->{$virtdev};
5283 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
5284 my $scfg = PVE
::Storage
::storage_config
($cfg, $d->{storeid
});
5286 # test if requested format is supported
5287 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $d->{storeid
});
5288 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
5289 $d->{format
} = $defFormat if !$supported;
5291 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $d->{storeid
}, $vmid,
5292 $d->{format
}, undef, $alloc_size);
5293 print STDERR
"new volume ID is '$volid'\n";
5294 $d->{volid
} = $volid;
5295 my $path = PVE
::Storage
::path
($cfg, $volid);
5297 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
5299 my $write_zeros = 1;
5300 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
5304 print $fifofh "format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
5306 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
5307 $map->{$virtdev} = $volid;
5310 $fh->seek(0, 0) || die "seek failed - $!\n";
5312 my $outfd = new IO
::File
($tmpfn, "w") ||
5313 die "unable to write config for VM $vmid\n";
5315 my $cookie = { netcount
=> 0 };
5316 while (defined(my $line = <$fh>)) {
5317 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
5326 local $SIG{INT
} = $SIG{TERM
} = $SIG{QUIT
} = $SIG{HUP
} = $SIG{PIPE
} = sub {
5327 die "interrupted by signal\n";
5329 local $SIG{ALRM
} = sub { die "got timeout\n"; };
5331 $oldtimeout = alarm($timeout);
5338 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
5339 my ($dev_id, $size, $devname) = ($1, $2, $3);
5340 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
5341 } elsif ($line =~ m/^CTIME: /) {
5342 # we correctly received the vma config, so we can disable
5343 # the timeout now for disk allocation (set to 10 minutes, so
5344 # that we always timeout if something goes wrong)
5347 print $fifofh "done\n";
5348 my $tmp = $oldtimeout || 0;
5349 $oldtimeout = undef;
5355 print "restore vma archive: $cmd\n";
5356 run_command
($cmd, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
5360 alarm($oldtimeout) if $oldtimeout;
5363 foreach my $devname (keys %$devinfo) {
5364 my $volid = $devinfo->{$devname}->{volid
};
5365 push @$vollist, $volid if $volid;
5368 my $cfg = PVE
::Storage
::config
();
5369 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
5377 foreach my $devname (keys %$devinfo) {
5378 my $volid = $devinfo->{$devname}->{volid
};
5381 if ($volid =~ m
|^/|) {
5382 unlink $volid || die 'unlink failed\n';
5384 PVE
::Storage
::vdisk_free
($cfg, $volid);
5386 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5388 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5395 rename($tmpfn, $conffile) ||
5396 die "unable to commit configuration file '$conffile'\n";
5398 PVE
::Cluster
::cfs_update
(); # make sure we read new file
5400 eval { rescan
($vmid, 1); };
5404 sub restore_tar_archive
{
5405 my ($archive, $vmid, $user, $opts) = @_;
5407 if ($archive ne '-') {
5408 my $firstfile = tar_archive_read_firstfile
($archive);
5409 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
5410 if $firstfile ne 'qemu-server.conf';
5413 my $storecfg = PVE
::Storage
::config
();
5415 # destroy existing data - keep empty config
5416 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
5417 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
5419 my $tocmd = "/usr/lib/qemu-server/qmextract";
5421 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
5422 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
5423 $tocmd .= ' --prealloc' if $opts->{prealloc
};
5424 $tocmd .= ' --info' if $opts->{info
};
5426 # tar option "xf" does not autodetect compression when read from STDIN,
5427 # so we pipe to zcat
5428 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
5429 PVE
::Tools
::shellquote
("--to-command=$tocmd");
5431 my $tmpdir = "/var/tmp/vzdumptmp$$";
5434 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
5435 local $ENV{VZDUMP_VMID
} = $vmid;
5436 local $ENV{VZDUMP_USER
} = $user;
5438 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5439 my $tmpfn = "$conffile.$$.tmp";
5441 # disable interrupts (always do cleanups)
5442 local $SIG{INT
} = $SIG{TERM
} = $SIG{QUIT
} = $SIG{HUP
} = sub {
5443 print STDERR
"got interrupt - ignored\n";
5448 local $SIG{INT
} = $SIG{TERM
} = $SIG{QUIT
} = $SIG{HUP
} = $SIG{PIPE
} = sub {
5449 die "interrupted by signal\n";
5452 if ($archive eq '-') {
5453 print "extracting archive from STDIN\n";
5454 run_command
($cmd, input
=> "<&STDIN");
5456 print "extracting archive '$archive'\n";
5460 return if $opts->{info
};
5464 my $statfile = "$tmpdir/qmrestore.stat";
5465 if (my $fd = IO
::File-
>new($statfile, "r")) {
5466 while (defined (my $line = <$fd>)) {
5467 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5468 $map->{$1} = $2 if $1;
5470 print STDERR
"unable to parse line in statfile - $line\n";
5476 my $confsrc = "$tmpdir/qemu-server.conf";
5478 my $srcfd = new IO
::File
($confsrc, "r") ||
5479 die "unable to open file '$confsrc'\n";
5481 my $outfd = new IO
::File
($tmpfn, "w") ||
5482 die "unable to write config for VM $vmid\n";
5484 my $cookie = { netcount
=> 0 };
5485 while (defined (my $line = <$srcfd>)) {
5486 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
5498 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
5505 rename $tmpfn, $conffile ||
5506 die "unable to commit configuration file '$conffile'\n";
5508 PVE
::Cluster
::cfs_update
(); # make sure we read new file
5510 eval { rescan
($vmid, 1); };
5514 sub foreach_writable_storage
{
5515 my ($conf, $func) = @_;
5519 foreach my $ds (keys %$conf) {
5520 next if !is_valid_drivename
($ds);
5522 my $drive = parse_drive
($ds, $conf->{$ds});
5524 next if drive_is_cdrom
($drive);
5526 my $volid = $drive->{file
};
5528 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
5529 $sidhash->{$sid} = $sid if $sid;
5532 foreach my $sid (sort keys %$sidhash) {
5537 sub do_snapshots_with_qemu
{
5538 my ($storecfg, $volid) = @_;
5540 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
5542 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
5543 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
5547 if ($volid =~ m/\.(qcow2|qed)$/){
5554 sub qga_check_running
{
5557 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
5559 warn "Qemu Guest Agent are not running - $@";
5565 sub template_create
{
5566 my ($vmid, $conf, $disk) = @_;
5568 my $storecfg = PVE
::Storage
::config
();
5570 foreach_drive
($conf, sub {
5571 my ($ds, $drive) = @_;
5573 return if drive_is_cdrom
($drive);
5574 return if $disk && $ds ne $disk;
5576 my $volid = $drive->{file
};
5577 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
5579 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
5580 $drive->{file
} = $voliddst;
5581 $conf->{$ds} = print_drive
($vmid, $drive);
5582 PVE
::QemuConfig-
>write_config($vmid, $conf);
5586 sub qemu_img_convert
{
5587 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
5589 my $storecfg = PVE
::Storage
::config
();
5590 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
5591 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
5593 if ($src_storeid && $dst_storeid) {
5595 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
5597 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
5598 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
5600 my $src_format = qemu_img_format
($src_scfg, $src_volname);
5601 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
5603 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
5604 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
5607 push @$cmd, '/usr/bin/qemu-img', 'convert', '-t', 'writeback', '-p', '-n';
5608 push @$cmd, '-s', $snapname if($snapname && $src_format eq "qcow2");
5609 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
5610 if ($is_zero_initialized) {
5611 push @$cmd, "zeroinit:$dst_path";
5613 push @$cmd, $dst_path;
5618 if($line =~ m/\((\S+)\/100\
%\)/){
5620 my $transferred = int($size * $percent / 100);
5621 my $remaining = $size - $transferred;
5623 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
5628 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
5630 die "copy failed: $err" if $err;
5634 sub qemu_img_format
{
5635 my ($scfg, $volname) = @_;
5637 if ($scfg->{path
} && $volname =~ m/\.(raw|cow|qcow|qcow2|qed|vmdk|cloop)$/) {
5644 sub qemu_drive_mirror
{
5645 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized) = @_;
5647 my $storecfg = PVE
::Storage
::config
();
5648 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
5650 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
5652 my $format = qemu_img_format
($dst_scfg, $dst_volname);
5654 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
5656 my $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
5658 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
5659 $opts->{format
} = $format if $format;
5661 print "drive mirror is starting (scanning bitmap) : this step can take some minutes/hours, depend of disk size and storage speed\n";
5663 my $finish_job = sub {
5665 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
5666 my $stat = @$stats[0];
5673 vm_mon_cmd
($vmid, "drive-mirror", %$opts);
5675 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
5676 my $stat = @$stats[0];
5677 die "mirroring job seem to have die. Maybe do you have bad sectors?" if !$stat;
5678 die "error job is not mirroring" if $stat->{type
} ne "mirror";
5680 my $busy = $stat->{busy
};
5681 my $ready = $stat->{ready
};
5683 if (my $total = $stat->{len
}) {
5684 my $transferred = $stat->{offset
} || 0;
5685 my $remaining = $total - $transferred;
5686 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
5688 print "transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
5692 if ($stat->{ready
} eq 'true') {
5694 last if $vmiddst != $vmid;
5696 # try to switch the disk if source and destination are on the same guest
5697 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> "drive-$drive") };
5702 die $@ if $@ !~ m/cannot be completed/;
5711 my $cancel_job = sub {
5712 vm_mon_cmd
($vmid, "block-job-cancel", device
=> "drive-$drive");
5717 eval { &$cancel_job(); };
5718 die "mirroring error: $err";
5721 if ($vmiddst != $vmid) {
5722 # if we clone a disk for a new target vm, we don't switch the disk
5723 &$cancel_job(); # so we call block-job-cancel
5728 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
5729 $newvmid, $storage, $format, $full, $newvollist) = @_;
5734 print "create linked clone of drive $drivename ($drive->{file})\n";
5735 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
5736 push @$newvollist, $newvolid;
5738 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
5739 $storeid = $storage if $storage;
5741 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
5743 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
5744 $format = qemu_img_format
($scfg, $volname);
5747 # test if requested format is supported - else use default
5748 my $supported = grep { $_ eq $format } @$validFormats;
5749 $format = $defFormat if !$supported;
5751 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
5753 print "create full clone of drive $drivename ($drive->{file})\n";
5754 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $format, undef, ($size/1024));
5755 push @$newvollist, $newvolid;
5757 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
5759 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
5760 if (!$running || $snapname) {
5761 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
5763 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit);
5767 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
5770 $disk->{format
} = undef;
5771 $disk->{file
} = $newvolid;
5772 $disk->{size
} = $size;
5777 # this only works if VM is running
5778 sub get_current_qemu_machine
{
5781 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
5782 my $res = vm_qmp_command
($vmid, $cmd);
5784 my ($current, $default);
5785 foreach my $e (@$res) {
5786 $default = $e->{name
} if $e->{'is-default'};
5787 $current = $e->{name
} if $e->{'is-current'};
5790 # fallback to the default machine if current is not supported by qemu
5791 return $current || $default || 'pc';
5794 sub qemu_machine_feature_enabled
{
5795 my ($machine, $kvmver, $version_major, $version_minor) = @_;
5800 if ($machine && $machine =~ m/^(pc(-i440fx|-q35)?-(\d+)\.(\d+))/) {
5802 $current_major = $3;
5803 $current_minor = $4;
5805 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
5807 $current_major = $1;
5808 $current_minor = $2;
5811 return 1 if $current_major >= $version_major && $current_minor >= $version_minor;
5816 sub qemu_machine_pxe
{
5817 my ($vmid, $conf, $machine) = @_;
5819 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
5821 foreach my $opt (keys %$conf) {
5822 next if $opt !~ m/^net(\d+)$/;
5823 my $net = PVE
::QemuServer
::parse_net
($conf->{$opt});
5825 my $romfile = PVE
::QemuServer
::vm_mon_cmd_nocheck
($vmid, 'qom-get', path
=> $opt, property
=> 'romfile');
5826 return $machine.".pxe" if $romfile =~ m/pxe/;
5833 sub qemu_use_old_bios_files
{
5834 my ($machine_type) = @_;
5836 return if !$machine_type;
5838 my $use_old_bios_files = undef;
5840 if ($machine_type =~ m/^(\S+)\.pxe$/) {
5842 $use_old_bios_files = 1;
5844 my $kvmver = kvm_user_version
();
5845 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
5846 # load new efi bios files on migration. So this hack is required to allow
5847 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
5848 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
5849 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
5852 return ($use_old_bios_files, $machine_type);
5859 dir_glob_foreach
("$pcisysfs/devices", '[a-f0-9]{4}:([a-f0-9]{2}:[a-f0-9]{2})\.([0-9])', sub {
5860 my (undef, $id, $function) = @_;
5861 my $res = { id
=> $id, function
=> $function};
5862 push @{$devices->{$id}}, $res;
5868 sub vm_iothreads_list
{
5871 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
5874 foreach my $iothread (@$res) {
5875 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
5882 my ($conf, $drive) = @_;
5886 if ($conf->{scsihw
} && ($conf->{scsihw
} =~ m/^lsi/)) {
5888 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
5894 my $controller = int($drive->{index} / $maxdev);
5895 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
5897 return ($maxdev, $controller, $controller_prefix);
5900 # bash completion helper
5902 sub complete_backup_archives
{
5903 my ($cmdname, $pname, $cvalue) = @_;
5905 my $cfg = PVE
::Storage
::config
();
5909 if ($cvalue =~ m/^([^:]+):/) {
5913 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
5916 foreach my $id (keys %$data) {
5917 foreach my $item (@{$data->{$id}}) {
5918 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
5919 push @$res, $item->{volid
} if defined($item->{volid
});
5926 my $complete_vmid_full = sub {
5929 my $idlist = vmstatus
();
5933 foreach my $id (keys %$idlist) {
5934 my $d = $idlist->{$id};
5935 if (defined($running)) {
5936 next if $d->{template
};
5937 next if $running && $d->{status
} ne 'running';
5938 next if !$running && $d->{status
} eq 'running';
5947 return &$complete_vmid_full();
5950 sub complete_vmid_stopped
{
5951 return &$complete_vmid_full(0);
5954 sub complete_vmid_running
{
5955 return &$complete_vmid_full(1);
5958 sub complete_storage
{
5960 my $cfg = PVE
::Storage
::config
();
5961 my $ids = $cfg->{ids
};
5964 foreach my $sid (keys %$ids) {
5965 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
5966 next if !$ids->{$sid}->{content
}->{images
};