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 = {
3877 # hotplug changes in [PENDING]
3878 # $selection hash can be used to only apply specified options, for
3879 # example: { cores => 1 } (only apply changed 'cores
')
3880 # $errors ref is used to return error messages
3881 sub vmconfig_hotplug_pending {
3882 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
3884 my $defaults = load_defaults();
3886 # commit values which do not have any impact on running VM first
3887 # Note: those option cannot raise errors, we we do not care about
3888 # $selection and always apply them.
3890 my $add_error = sub {
3891 my ($opt, $msg) = @_;
3892 $errors->{$opt} = "hotplug problem - $msg";
3896 foreach my $opt (keys %{$conf->{pending}}) { # add/change
3897 if ($fast_plug_option->{$opt}) {
3898 $conf->{$opt} = $conf->{pending}->{$opt};
3899 delete $conf->{pending}->{$opt};
3905 PVE::QemuConfig->write_config($vmid, $conf);
3906 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
3909 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
3911 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
3912 while (my ($opt, $force) = each %$pending_delete_hash) {
3913 next if $selection && !$selection->{$opt};
3915 if ($opt eq 'hotplug
') {
3916 die "skip\n" if ($conf->{hotplug} =~ /memory/);
3917 } elsif ($opt eq 'tablet
') {
3918 die "skip\n" if !$hotplug_features->{usb};
3919 if ($defaults->{tablet}) {
3920 vm_deviceplug($storecfg, $conf, $vmid, $opt);
3922 vm_deviceunplug($vmid, $conf, $opt);
3924 } elsif ($opt =~ m/^usb\d+/) {
3926 # since we cannot reliably hot unplug usb devices
3927 # we are disabling it
3928 die "skip\n" if !$hotplug_features->{usb} || $conf->{$opt} =~ m/spice/i;
3929 vm_deviceunplug($vmid, $conf, $opt);
3930 } elsif ($opt eq 'vcpus
') {
3931 die "skip\n" if !$hotplug_features->{cpu};
3932 qemu_cpu_hotplug($vmid, $conf, undef);
3933 } elsif ($opt eq 'balloon
') {
3934 # enable balloon device is not hotpluggable
3935 die "skip\n" if !defined($conf->{balloon}) || $conf->{balloon};
3936 } elsif ($fast_plug_option->{$opt}) {
3938 } elsif ($opt =~ m/^net(\d+)$/) {
3939 die "skip\n" if !$hotplug_features->{network};
3940 vm_deviceunplug($vmid, $conf, $opt);
3941 } elsif (is_valid_drivename($opt)) {
3942 die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
3943 vm_deviceunplug($vmid, $conf, $opt);
3944 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
3945 } elsif ($opt =~ m/^memory$/) {
3946 die "skip\n" if !$hotplug_features->{memory};
3947 PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
3948 } elsif ($opt eq 'cpuunits
') {
3949 cgroups_write("cpu", $vmid, "cpu.shares", $defaults->{cpuunits});
3950 } elsif ($opt eq 'cpulimit
') {
3951 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", -1);
3957 &$add_error($opt, $err) if $err ne "skip\n";
3959 # save new config if hotplug was successful
3960 delete $conf->{$opt};
3961 vmconfig_undelete_pending_option($conf, $opt);
3962 PVE::QemuConfig->write_config($vmid, $conf);
3963 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
3967 foreach my $opt (keys %{$conf->{pending}}) {
3968 next if $selection && !$selection->{$opt};
3969 my $value = $conf->{pending}->{$opt};
3971 if ($opt eq 'hotplug
') {
3972 die "skip\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
3973 } elsif ($opt eq 'tablet
') {
3974 die "skip\n" if !$hotplug_features->{usb};
3976 vm_deviceplug($storecfg, $conf, $vmid, $opt);
3977 } elsif ($value == 0) {
3978 vm_deviceunplug($vmid, $conf, $opt);
3980 } elsif ($opt =~ m/^usb\d+$/) {
3982 # since we cannot reliably hot unplug usb devices
3983 # we are disabling it
3984 die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
3985 my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
3986 die "skip\n" if !$d;
3987 qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d);
3988 } elsif ($opt eq 'vcpus
') {
3989 die "skip\n" if !$hotplug_features->{cpu};
3990 qemu_cpu_hotplug($vmid, $conf, $value);
3991 } elsif ($opt eq 'balloon
') {
3992 # enable/disable balloning device is not hotpluggable
3993 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
3994 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
3995 die "skip\n" if $old_balloon_enabled != $new_balloon_enabled;
3997 # allow manual ballooning if shares is set to zero
3998 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
3999 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4000 vm_mon_cmd($vmid, "balloon", value => $balloon*1024*1024);
4002 } elsif ($opt =~ m/^net(\d+)$/) {
4003 # some changes can be done without hotplug
4004 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4005 $vmid, $opt, $value);
4006 } elsif (is_valid_drivename($opt)) {
4007 # some changes can be done without hotplug
4008 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4009 $vmid, $opt, $value, 1);
4010 } elsif ($opt =~ m/^memory$/) { #dimms
4011 die "skip\n" if !$hotplug_features->{memory};
4012 $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4013 } elsif ($opt eq 'cpuunits
') {
4014 cgroups_write("cpu", $vmid, "cpu.shares", $conf->{pending}->{$opt});
4015 } elsif ($opt eq 'cpulimit
') {
4016 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4017 cgroups_write("cpu", $vmid, "cpu.cfs_quota_us", $cpulimit);
4019 die "skip\n"; # skip non-hot-pluggable options
4023 &$add_error($opt, $err) if $err ne "skip\n";
4025 # save new config if hotplug was successful
4026 $conf->{$opt} = $value;
4027 delete $conf->{pending}->{$opt};
4028 PVE::QemuConfig->write_config($vmid, $conf);
4029 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4034 sub try_deallocate_drive {
4035 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4037 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4038 my $volid = $drive->{file};
4039 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4040 my $sid = PVE::Storage::parse_volume_id($volid);
4041 $rpcenv->check($authuser, "/storage/$sid", ['Datastore
.AllocateSpace
']);
4043 # check if the disk is really unused
4044 die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
4045 if is_volume_in_use($storecfg, $conf, $key, $volid);
4046 PVE::Storage::vdisk_free($storecfg, $volid);
4049 # If vm is not owner of this disk remove from config
4057 sub vmconfig_delete_or_detach_drive {
4058 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4060 my $drive = parse_drive($opt, $conf->{$opt});
4062 my $rpcenv = PVE::RPCEnvironment::get();
4063 my $authuser = $rpcenv->get_user();
4066 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM
.Config
.Disk
']);
4067 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4069 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4073 sub vmconfig_apply_pending {
4074 my ($vmid, $conf, $storecfg) = @_;
4078 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4079 while (my ($opt, $force) = each %$pending_delete_hash) {
4080 die "internal error" if $opt =~ m/^unused/;
4081 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4082 if (!defined($conf->{$opt})) {
4083 vmconfig_undelete_pending_option($conf, $opt);
4084 PVE::QemuConfig->write_config($vmid, $conf);
4085 } elsif (is_valid_drivename($opt)) {
4086 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4087 vmconfig_undelete_pending_option($conf, $opt);
4088 delete $conf->{$opt};
4089 PVE::QemuConfig->write_config($vmid, $conf);
4091 vmconfig_undelete_pending_option($conf, $opt);
4092 delete $conf->{$opt};
4093 PVE::QemuConfig->write_config($vmid, $conf);
4097 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4099 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4100 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4102 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4103 # skip if nothing changed
4104 } elsif (is_valid_drivename($opt)) {
4105 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4106 if defined($conf->{$opt});
4107 $conf->{$opt} = $conf->{pending}->{$opt};
4109 $conf->{$opt} = $conf->{pending}->{$opt};
4112 delete $conf->{pending}->{$opt};
4113 PVE::QemuConfig->write_config($vmid, $conf);
4117 my $safe_num_ne = sub {
4120 return 0 if !defined($a) && !defined($b);
4121 return 1 if !defined($a);
4122 return 1 if !defined($b);
4127 my $safe_string_ne = sub {
4130 return 0 if !defined($a) && !defined($b);
4131 return 1 if !defined($a);
4132 return 1 if !defined($b);
4137 sub vmconfig_update_net {
4138 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value) = @_;
4140 my $newnet = parse_net($value);
4142 if ($conf->{$opt}) {
4143 my $oldnet = parse_net($conf->{$opt});
4145 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4146 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4147 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4148 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4150 # for non online change, we try to hot-unplug
4151 die "skip\n" if !$hotplug;
4152 vm_deviceunplug($vmid, $conf, $opt);
4155 die "internal error" if $opt !~ m/net(\d+)/;
4156 my $iface = "tap${vmid}i$1";
4158 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4159 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4160 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4161 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4162 PVE::Network::tap_unplug($iface);
4163 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4164 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4165 # Rate can be applied on its own but any change above needs to
4166 # include the rate in tap_plug since OVS resets everything.
4167 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4170 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4171 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4179 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet);
4185 sub vmconfig_update_disk {
4186 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force) = @_;
4188 # fixme: do we need force?
4190 my $drive = parse_drive($opt, $value);
4192 if ($conf->{$opt}) {
4194 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4196 my $media = $drive->{media} || 'disk
';
4197 my $oldmedia = $old_drive->{media} || 'disk
';
4198 die "unable to change media type\n" if $media ne $oldmedia;
4200 if (!drive_is_cdrom($old_drive)) {
4202 if ($drive->{file} ne $old_drive->{file}) {
4204 die "skip\n" if !$hotplug;
4206 # unplug and register as unused
4207 vm_deviceunplug($vmid, $conf, $opt);
4208 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4211 # update existing disk
4213 # skip non hotpluggable value
4214 if (&$safe_num_ne($drive->{discard}, $old_drive->{discard}) ||
4215 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4216 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4217 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
4222 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4223 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4224 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4225 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4226 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4227 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4228 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4229 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4230 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4231 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4232 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4233 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max})) {
4235 qemu_block_set_io_throttle($vmid,"drive-$opt",
4236 ($drive->{mbps} || 0)*1024*1024,
4237 ($drive->{mbps_rd} || 0)*1024*1024,
4238 ($drive->{mbps_wr} || 0)*1024*1024,
4239 $drive->{iops} || 0,
4240 $drive->{iops_rd} || 0,
4241 $drive->{iops_wr} || 0,
4242 ($drive->{mbps_max} || 0)*1024*1024,
4243 ($drive->{mbps_rd_max} || 0)*1024*1024,
4244 ($drive->{mbps_wr_max} || 0)*1024*1024,
4245 $drive->{iops_max} || 0,
4246 $drive->{iops_rd_max} || 0,
4247 $drive->{iops_wr_max} || 0);
4256 if ($drive->{file} eq 'none
') {
4257 vm_mon_cmd($vmid, "eject",force => JSON::true,device => "drive-$opt");
4259 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4260 vm_mon_cmd($vmid, "eject", force => JSON::true,device => "drive-$opt"); # force eject if locked
4261 vm_mon_cmd($vmid, "change", device => "drive-$opt",target => "$path") if $path;
4269 die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4271 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
4272 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive);
4276 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
4277 $forcemachine, $spice_ticket) = @_;
4279 PVE::QemuConfig->lock_config($vmid, sub {
4280 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
4282 die "you can't start a vm
if it
's a template\n" if PVE::QemuConfig->is_template($conf);
4284 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4286 die "VM $vmid already running\n" if check_running($vmid, undef, $migratedfrom);
4288 if (!$statefile && scalar(keys %{$conf->{pending}})) {
4289 vmconfig_apply_pending($vmid, $conf, $storecfg);
4290 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4293 my $defaults = load_defaults();
4295 # set environment variable useful inside network script
4296 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
4298 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
4300 my $migrate_port = 0;
4303 if ($statefile eq 'tcp
') {
4304 my $localip = "localhost";
4305 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter
.cfg
');
4306 my $nodename = PVE::INotify::nodename();
4307 if ($datacenterconf->{migration_unsecure}) {
4308 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
4309 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4311 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4312 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4313 $migrate_uri = "tcp:${localip}:${migrate_port}";
4314 push @$cmd, '-incoming
', $migrate_uri;
4317 } elsif ($statefile eq 'unix
') {
4318 # should be default for secure migrations as a ssh TCP forward
4319 # tunnel is not deterministic reliable ready and fails regurarly
4320 # to set up in time, so use UNIX socket forwards
4321 my $socket_addr = "/run/qemu-server/$vmid.migrate";
4322 unlink $socket_addr;
4324 $migrate_uri = "unix:$socket_addr";
4326 push @$cmd, '-incoming
', $migrate_uri;
4330 push @$cmd, '-loadstate
', $statefile;
4337 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
4338 my $d = parse_hostpci($conf->{"hostpci$i"});
4340 my $pcidevices = $d->{pciid};
4341 foreach my $pcidevice (@$pcidevices) {
4342 my $pciid = $pcidevice->{id}.".".$pcidevice->{function};
4344 my $info = pci_device_info("0000:$pciid");
4345 die "IOMMU not present\n" if !check_iommu_support();
4346 die "no pci device info for device '$pciid'\n" if !$info;
4347 die "can't unbind
/bind pci group to vfio
'$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
4348 die "can
't reset pci device '$pciid'\n" if $info->{has_fl_reset} and !pci_dev_reset($info);
4352 PVE::Storage::activate_volumes($storecfg, $vollist);
4354 if (!check_running($vmid, 1) && -d "/sys/fs/cgroup/systemd/qemu.slice/$vmid.scope") {
4356 push @$cmd, '/bin/systemctl
', 'stop
', "$vmid.scope";
4357 eval { run_command($cmd); };
4360 my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
4361 : $defaults->{cpuunits};
4363 my %run_params = (timeout => $statefile ? undef : 30, umask => 0077);
4366 Slice => 'qemu
.slice
',
4368 CPUShares => $cpuunits
4371 if (my $cpulimit = $conf->{cpulimit}) {
4372 $properties{CPUQuota} = int($cpulimit * 100);
4374 $properties{timeout} = 10 if $statefile; # setting up the scope shoul be quick
4376 if ($conf->{hugepages}) {
4379 my $hugepages_topology = PVE::QemuServer::Memory::hugepages_topology($conf);
4380 my $hugepages_host_topology = PVE::QemuServer::Memory::hugepages_host_topology();
4382 PVE::QemuServer::Memory::hugepages_mount();
4383 PVE::QemuServer::Memory::hugepages_allocate($hugepages_topology, $hugepages_host_topology);
4386 PVE::Tools::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4387 run_command($cmd, %run_params);
4391 PVE::QemuServer::Memory::hugepages_reset($hugepages_host_topology);
4395 PVE::QemuServer::Memory::hugepages_pre_deallocate($hugepages_topology);
4397 eval { PVE::QemuServer::Memory::hugepages_update_locked($code); };
4401 PVE::Tools::enter_systemd_scope($vmid, "Proxmox VE VM $vmid", %properties);
4402 run_command($cmd, %run_params);
4407 # deactivate volumes if start fails
4408 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
4409 die "start failed: $err";
4412 print "migration listens on $migrate_uri\n" if $migrate_uri;
4414 if ($statefile && $statefile ne 'tcp
') {
4415 eval { vm_mon_cmd_nocheck($vmid, "cont"); };
4419 if ($migratedfrom) {
4422 set_migration_caps($vmid);
4427 print "spice listens on port $spice_port\n";
4428 if ($spice_ticket) {
4429 vm_mon_cmd_nocheck($vmid, "set_password", protocol => 'spice
', password => $spice_ticket);
4430 vm_mon_cmd_nocheck($vmid, "expire_password", protocol => 'spice
', time => "+30");
4436 if (!$statefile && (!defined($conf->{balloon}) || $conf->{balloon})) {
4437 vm_mon_cmd_nocheck($vmid, "balloon", value => $conf->{balloon}*1024*1024)
4438 if $conf->{balloon};
4441 foreach my $opt (keys %$conf) {
4442 next if $opt !~ m/^net\d+$/;
4443 my $nicconf = parse_net($conf->{$opt});
4444 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
4448 vm_mon_cmd_nocheck($vmid, 'qom-set
',
4449 path => "machine/peripheral/balloon0",
4450 property => "guest-stats-polling-interval",
4451 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
4457 my ($vmid, $execute, %params) = @_;
4459 my $cmd = { execute => $execute, arguments => \%params };
4460 vm_qmp_command($vmid, $cmd);
4463 sub vm_mon_cmd_nocheck {
4464 my ($vmid, $execute, %params) = @_;
4466 my $cmd = { execute => $execute, arguments => \%params };
4467 vm_qmp_command($vmid, $cmd, 1);
4470 sub vm_qmp_command {
4471 my ($vmid, $cmd, $nocheck) = @_;
4476 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
4477 $timeout = $cmd->{arguments}->{timeout};
4478 delete $cmd->{arguments}->{timeout};
4482 die "VM $vmid not running\n" if !check_running($vmid, $nocheck);
4483 my $sname = qmp_socket($vmid);
4484 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
4485 my $qmpclient = PVE::QMPClient->new();
4487 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
4488 } elsif (-e "${var_run_tmpdir}/$vmid.mon") {
4489 die "can't execute complex command on old monitor
- stop
/start your vm to fix the problem
\n"
4490 if scalar(%{$cmd->{arguments}});
4491 vm_monitor_command($vmid, $cmd->{execute}, $nocheck);
4493 die "unable to
open monitor
socket\n";
4497 syslog("err
", "VM
$vmid qmp command failed
- $err");
4504 sub vm_human_monitor_command {
4505 my ($vmid, $cmdline) = @_;
4510 execute => 'human-monitor-command',
4511 arguments => { 'command-line' => $cmdline},
4514 return vm_qmp_command($vmid, $cmd);
4517 sub vm_commandline {
4518 my ($storecfg, $vmid) = @_;
4520 my $conf = PVE::QemuConfig->load_config($vmid);
4522 my $defaults = load_defaults();
4524 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
4526 return join(' ', @$cmd);
4530 my ($vmid, $skiplock) = @_;
4532 PVE::QemuConfig->lock_config($vmid, sub {
4534 my $conf = PVE::QemuConfig->load_config($vmid);
4536 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4538 vm_mon_cmd($vmid, "system_reset
");
4542 sub get_vm_volumes {
4546 foreach_volid($conf, sub {
4547 my ($volid, $is_cdrom) = @_;
4549 return if $volid =~ m|^/|;
4551 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
4554 push @$vollist, $volid;
4560 sub vm_stop_cleanup {
4561 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
4566 my $vollist = get_vm_volumes($conf);
4567 PVE::Storage::deactivate_volumes($storecfg, $vollist);
4570 foreach my $ext (qw(mon qmp pid vnc qga)) {
4571 unlink "/var/run/qemu-server/${vmid}.$ext";
4574 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
4576 warn $@ if $@; # avoid errors - just warn
4579 # Note: use $nockeck to skip tests if VM configuration file exists.
4580 # We need that when migration VMs to other nodes (files already moved)
4581 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
4583 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
4585 $force = 1 if !defined($force) && !$shutdown;
4588 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
4589 kill 15, $pid if $pid;
4590 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
4591 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
4595 PVE
::QemuConfig-
>lock_config($vmid, sub {
4597 my $pid = check_running
($vmid, $nocheck);
4602 $conf = PVE
::QemuConfig-
>load_config($vmid);
4603 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
4604 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
4605 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
4606 $timeout = $opts->{down
} if $opts->{down
};
4610 $timeout = 60 if !defined($timeout);
4614 if (defined($conf) && $conf->{agent
}) {
4615 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
4617 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
4620 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
4627 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
4632 if ($count >= $timeout) {
4634 warn "VM still running - terminating now with SIGTERM\n";
4637 die "VM quit/powerdown failed - got timeout\n";
4640 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
4645 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
4648 die "VM quit/powerdown failed\n";
4656 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
4661 if ($count >= $timeout) {
4662 warn "VM still running - terminating now with SIGKILL\n";
4667 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
4672 my ($vmid, $skiplock) = @_;
4674 PVE
::QemuConfig-
>lock_config($vmid, sub {
4676 my $conf = PVE
::QemuConfig-
>load_config($vmid);
4678 PVE
::QemuConfig-
>check_lock($conf)
4679 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
4681 vm_mon_cmd
($vmid, "stop");
4686 my ($vmid, $skiplock, $nocheck) = @_;
4688 PVE
::QemuConfig-
>lock_config($vmid, sub {
4692 my $conf = PVE
::QemuConfig-
>load_config($vmid);
4694 PVE
::QemuConfig-
>check_lock($conf)
4695 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
4697 vm_mon_cmd
($vmid, "cont");
4700 vm_mon_cmd_nocheck
($vmid, "cont");
4706 my ($vmid, $skiplock, $key) = @_;
4708 PVE
::QemuConfig-
>lock_config($vmid, sub {
4710 my $conf = PVE
::QemuConfig-
>load_config($vmid);
4712 # there is no qmp command, so we use the human monitor command
4713 vm_human_monitor_command
($vmid, "sendkey $key");
4718 my ($storecfg, $vmid, $skiplock) = @_;
4720 PVE
::QemuConfig-
>lock_config($vmid, sub {
4722 my $conf = PVE
::QemuConfig-
>load_config($vmid);
4724 if (!check_running
($vmid)) {
4725 destroy_vm
($storecfg, $vmid, undef, $skiplock);
4727 die "VM $vmid is running - destroy failed\n";
4735 my ($filename, $buf) = @_;
4737 my $fh = IO
::File-
>new($filename, "w");
4738 return undef if !$fh;
4740 my $res = print $fh $buf;
4747 sub pci_device_info
{
4752 return undef if $name !~ m/^([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\.([a-f0-9])$/;
4753 my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4);
4755 my $irq = file_read_firstline
("$pcisysfs/devices/$name/irq");
4756 return undef if !defined($irq) || $irq !~ m/^\d+$/;
4758 my $vendor = file_read_firstline
("$pcisysfs/devices/$name/vendor");
4759 return undef if !defined($vendor) || $vendor !~ s/^0x//;
4761 my $product = file_read_firstline
("$pcisysfs/devices/$name/device");
4762 return undef if !defined($product) || $product !~ s/^0x//;
4767 product
=> $product,
4773 has_fl_reset
=> -f
"$pcisysfs/devices/$name/reset" || 0,
4782 my $name = $dev->{name
};
4784 my $fn = "$pcisysfs/devices/$name/reset";
4786 return file_write
($fn, "1");
4789 sub pci_dev_bind_to_vfio
{
4792 my $name = $dev->{name
};
4794 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
4796 if (!-d
$vfio_basedir) {
4797 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
4799 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
4801 my $testdir = "$vfio_basedir/$name";
4802 return 1 if -d
$testdir;
4804 my $data = "$dev->{vendor} $dev->{product}";
4805 return undef if !file_write
("$vfio_basedir/new_id", $data);
4807 my $fn = "$pcisysfs/devices/$name/driver/unbind";
4808 if (!file_write
($fn, $name)) {
4809 return undef if -f
$fn;
4812 $fn = "$vfio_basedir/bind";
4813 if (! -d
$testdir) {
4814 return undef if !file_write
($fn, $name);
4820 sub pci_dev_group_bind_to_vfio
{
4823 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
4825 if (!-d
$vfio_basedir) {
4826 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
4828 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
4830 # get IOMMU group devices
4831 opendir(my $D, "$pcisysfs/devices/0000:$pciid/iommu_group/devices/") || die "Cannot open iommu_group: $!\n";
4832 my @devs = grep /^0000:/, readdir($D);
4835 foreach my $pciid (@devs) {
4836 $pciid =~ m/^([:\.\da-f]+)$/ or die "PCI ID $pciid not valid!\n";
4838 # pci bridges, switches or root ports are not supported
4839 # they have a pci_bus subdirectory so skip them
4840 next if (-e
"$pcisysfs/devices/$pciid/pci_bus");
4842 my $info = pci_device_info
($1);
4843 pci_dev_bind_to_vfio
($info) || die "Cannot bind $pciid to vfio\n";
4849 # vzdump restore implementaion
4851 sub tar_archive_read_firstfile
{
4852 my $archive = shift;
4854 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
4856 # try to detect archive type first
4857 my $pid = open (my $fh, '-|', 'tar', 'tf', $archive) ||
4858 die "unable to open file '$archive'\n";
4859 my $firstfile = <$fh>;
4863 die "ERROR: archive contaions no data\n" if !$firstfile;
4869 sub tar_restore_cleanup
{
4870 my ($storecfg, $statfile) = @_;
4872 print STDERR
"starting cleanup\n";
4874 if (my $fd = IO
::File-
>new($statfile, "r")) {
4875 while (defined(my $line = <$fd>)) {
4876 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
4879 if ($volid =~ m
|^/|) {
4880 unlink $volid || die 'unlink failed\n';
4882 PVE
::Storage
::vdisk_free
($storecfg, $volid);
4884 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
4886 print STDERR
"unable to cleanup '$volid' - $@" if $@;
4888 print STDERR
"unable to parse line in statfile - $line";
4895 sub restore_archive
{
4896 my ($archive, $vmid, $user, $opts) = @_;
4898 my $format = $opts->{format
};
4901 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
4902 $format = 'tar' if !$format;
4904 } elsif ($archive =~ m/\.tar$/) {
4905 $format = 'tar' if !$format;
4906 } elsif ($archive =~ m/.tar.lzo$/) {
4907 $format = 'tar' if !$format;
4909 } elsif ($archive =~ m/\.vma$/) {
4910 $format = 'vma' if !$format;
4911 } elsif ($archive =~ m/\.vma\.gz$/) {
4912 $format = 'vma' if !$format;
4914 } elsif ($archive =~ m/\.vma\.lzo$/) {
4915 $format = 'vma' if !$format;
4918 $format = 'vma' if !$format; # default
4921 # try to detect archive format
4922 if ($format eq 'tar') {
4923 return restore_tar_archive
($archive, $vmid, $user, $opts);
4925 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
4929 sub restore_update_config_line
{
4930 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
4932 return if $line =~ m/^\#qmdump\#/;
4933 return if $line =~ m/^\#vzdump\#/;
4934 return if $line =~ m/^lock:/;
4935 return if $line =~ m/^unused\d+:/;
4936 return if $line =~ m/^parent:/;
4937 return if $line =~ m/^template:/; # restored VM is never a template
4939 my $dc = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
4940 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
4941 # try to convert old 1.X settings
4942 my ($id, $ind, $ethcfg) = ($1, $2, $3);
4943 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
4944 my ($model, $macaddr) = split(/\=/, $devconfig);
4945 $macaddr = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if !$macaddr || $unique;
4948 bridge
=> "vmbr$ind",
4949 macaddr
=> $macaddr,
4951 my $netstr = print_net
($net);
4953 print $outfd "net$cookie->{netcount}: $netstr\n";
4954 $cookie->{netcount
}++;
4956 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
4957 my ($id, $netstr) = ($1, $2);
4958 my $net = parse_net
($netstr);
4959 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
($dc->{mac_prefix
}) if $net->{macaddr
};
4960 $netstr = print_net
($net);
4961 print $outfd "$id: $netstr\n";
4962 } elsif ($line =~ m/^((ide|scsi|virtio|sata)\d+):\s*(\S+)\s*$/) {
4965 my $di = parse_drive
($virtdev, $value);
4966 if (defined($di->{backup
}) && !$di->{backup
}) {
4967 print $outfd "#$line";
4968 } elsif ($map->{$virtdev}) {
4969 delete $di->{format
}; # format can change on restore
4970 $di->{file
} = $map->{$virtdev};
4971 $value = print_drive
($vmid, $di);
4972 print $outfd "$virtdev: $value\n";
4982 my ($cfg, $vmid) = @_;
4984 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
4986 my $volid_hash = {};
4987 foreach my $storeid (keys %$info) {
4988 foreach my $item (@{$info->{$storeid}}) {
4989 next if !($item->{volid
} && $item->{size
});
4990 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
4991 $volid_hash->{$item->{volid
}} = $item;
4998 sub is_volume_in_use
{
4999 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5001 my $path = PVE
::Storage
::path
($storecfg, $volid);
5003 my $scan_config = sub {
5004 my ($cref, $snapname) = @_;
5006 foreach my $key (keys %$cref) {
5007 my $value = $cref->{$key};
5008 if (is_valid_drivename
($key)) {
5009 next if $skip_drive && $key eq $skip_drive;
5010 my $drive = parse_drive
($key, $value);
5011 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5012 return 1 if $volid eq $drive->{file
};
5013 if ($drive->{file
} =~ m!^/!) {
5014 return 1 if $drive->{file
} eq $path;
5016 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5018 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5020 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5028 return 1 if &$scan_config($conf);
5032 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5033 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5039 sub update_disksize
{
5040 my ($vmid, $conf, $volid_hash) = @_;
5046 # Note: it is allowed to define multiple storages with same path (alias), so
5047 # we need to check both 'volid' and real 'path' (two different volid can point
5048 # to the same path).
5053 foreach my $opt (keys %$conf) {
5054 if (is_valid_drivename
($opt)) {
5055 my $drive = parse_drive
($opt, $conf->{$opt});
5056 my $volid = $drive->{file
};
5059 $used->{$volid} = 1;
5060 if ($volid_hash->{$volid} &&
5061 (my $path = $volid_hash->{$volid}->{path
})) {
5062 $usedpath->{$path} = 1;
5065 next if drive_is_cdrom
($drive);
5066 next if !$volid_hash->{$volid};
5068 $drive->{size
} = $volid_hash->{$volid}->{size
};
5069 my $new = print_drive
($vmid, $drive);
5070 if ($new ne $conf->{$opt}) {
5072 $conf->{$opt} = $new;
5077 # remove 'unusedX' entry if volume is used
5078 foreach my $opt (keys %$conf) {
5079 next if $opt !~ m/^unused\d+$/;
5080 my $volid = $conf->{$opt};
5081 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5082 if ($used->{$volid} || ($path && $usedpath->{$path})) {
5084 delete $conf->{$opt};
5088 foreach my $volid (sort keys %$volid_hash) {
5089 next if $volid =~ m/vm-$vmid-state-/;
5090 next if $used->{$volid};
5091 my $path = $volid_hash->{$volid}->{path
};
5092 next if !$path; # just to be sure
5093 next if $usedpath->{$path};
5095 PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5096 $usedpath->{$path} = 1; # avoid to add more than once (aliases)
5103 my ($vmid, $nolock) = @_;
5105 my $cfg = PVE
::Storage
::config
();
5107 my $volid_hash = scan_volids
($cfg, $vmid);
5109 my $updatefn = sub {
5112 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5114 PVE
::QemuConfig-
>check_lock($conf);
5117 foreach my $volid (keys %$volid_hash) {
5118 my $info = $volid_hash->{$volid};
5119 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5122 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5124 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes;
5127 if (defined($vmid)) {
5131 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5134 my $vmlist = config_list
();
5135 foreach my $vmid (keys %$vmlist) {
5139 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5145 sub restore_vma_archive
{
5146 my ($archive, $vmid, $user, $opts, $comp) = @_;
5148 my $input = $archive eq '-' ?
"<&STDIN" : undef;
5149 my $readfrom = $archive;
5154 my $qarchive = PVE
::Tools
::shellquote
($archive);
5155 if ($comp eq 'gzip') {
5156 $uncomp = "zcat $qarchive|";
5157 } elsif ($comp eq 'lzop') {
5158 $uncomp = "lzop -d -c $qarchive|";
5160 die "unknown compression method '$comp'\n";
5165 my $tmpdir = "/var/tmp/vzdumptmp$$";
5168 # disable interrupts (always do cleanups)
5169 local $SIG{INT
} = $SIG{TERM
} = $SIG{QUIT
} = $SIG{HUP
} = sub {
5170 warn "got interrupt - ignored\n";
5173 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
5174 POSIX
::mkfifo
($mapfifo, 0600);
5177 my $openfifo = sub {
5178 open($fifofh, '>', $mapfifo) || die $!;
5181 my $cmd = "${uncomp}vma extract -v -r $mapfifo $readfrom $tmpdir";
5188 my $rpcenv = PVE
::RPCEnvironment
::get
();
5190 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5191 my $tmpfn = "$conffile.$$.tmp";
5193 # Note: $oldconf is undef if VM does not exists
5194 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
5195 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
5197 my $print_devmap = sub {
5198 my $virtdev_hash = {};
5200 my $cfgfn = "$tmpdir/qemu-server.conf";
5202 # we can read the config - that is already extracted
5203 my $fh = IO
::File-
>new($cfgfn, "r") ||
5204 "unable to read qemu-server.conf - $!\n";
5206 my $fwcfgfn = "$tmpdir/qemu-server.fw";
5208 my $pve_firewall_dir = '/etc/pve/firewall';
5209 mkdir $pve_firewall_dir; # make sure the dir exists
5210 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
5213 while (defined(my $line = <$fh>)) {
5214 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
5215 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
5216 die "archive does not contain data for drive '$virtdev'\n"
5217 if !$devinfo->{$devname};
5218 if (defined($opts->{storage
})) {
5219 $storeid = $opts->{storage
} || 'local';
5220 } elsif (!$storeid) {
5223 $format = 'raw' if !$format;
5224 $devinfo->{$devname}->{devname
} = $devname;
5225 $devinfo->{$devname}->{virtdev
} = $virtdev;
5226 $devinfo->{$devname}->{format
} = $format;
5227 $devinfo->{$devname}->{storeid
} = $storeid;
5229 # check permission on storage
5230 my $pool = $opts->{pool
}; # todo: do we need that?
5231 if ($user ne 'root@pam') {
5232 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
5235 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
5239 foreach my $devname (keys %$devinfo) {
5240 die "found no device mapping information for device '$devname'\n"
5241 if !$devinfo->{$devname}->{virtdev
};
5244 my $cfg = PVE
::Storage
::config
();
5246 # create empty/temp config
5248 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
5249 foreach_drive
($oldconf, sub {
5250 my ($ds, $drive) = @_;
5252 return if drive_is_cdrom
($drive);
5254 my $volid = $drive->{file
};
5256 return if !$volid || $volid =~ m
|^/|;
5258 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
5259 return if !$path || !$owner || ($owner != $vmid);
5261 # Note: only delete disk we want to restore
5262 # other volumes will become unused
5263 if ($virtdev_hash->{$ds}) {
5264 PVE
::Storage
::vdisk_free
($cfg, $volid);
5268 # delete vmstate files
5269 # since after the restore we have no snapshots anymore
5270 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
5271 my $snap = $oldconf->{snapshots
}->{$snapname};
5272 if ($snap->{vmstate
}) {
5273 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
5282 foreach my $virtdev (sort keys %$virtdev_hash) {
5283 my $d = $virtdev_hash->{$virtdev};
5284 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
5285 my $scfg = PVE
::Storage
::storage_config
($cfg, $d->{storeid
});
5287 # test if requested format is supported
5288 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $d->{storeid
});
5289 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
5290 $d->{format
} = $defFormat if !$supported;
5292 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $d->{storeid
}, $vmid,
5293 $d->{format
}, undef, $alloc_size);
5294 print STDERR
"new volume ID is '$volid'\n";
5295 $d->{volid
} = $volid;
5296 my $path = PVE
::Storage
::path
($cfg, $volid);
5298 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
5300 my $write_zeros = 1;
5301 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
5305 print $fifofh "format=$d->{format}:${write_zeros}:$d->{devname}=$path\n";
5307 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
5308 $map->{$virtdev} = $volid;
5311 $fh->seek(0, 0) || die "seek failed - $!\n";
5313 my $outfd = new IO
::File
($tmpfn, "w") ||
5314 die "unable to write config for VM $vmid\n";
5316 my $cookie = { netcount
=> 0 };
5317 while (defined(my $line = <$fh>)) {
5318 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
5327 local $SIG{INT
} = $SIG{TERM
} = $SIG{QUIT
} = $SIG{HUP
} = $SIG{PIPE
} = sub {
5328 die "interrupted by signal\n";
5330 local $SIG{ALRM
} = sub { die "got timeout\n"; };
5332 $oldtimeout = alarm($timeout);
5339 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
5340 my ($dev_id, $size, $devname) = ($1, $2, $3);
5341 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
5342 } elsif ($line =~ m/^CTIME: /) {
5343 # we correctly received the vma config, so we can disable
5344 # the timeout now for disk allocation (set to 10 minutes, so
5345 # that we always timeout if something goes wrong)
5348 print $fifofh "done\n";
5349 my $tmp = $oldtimeout || 0;
5350 $oldtimeout = undef;
5356 print "restore vma archive: $cmd\n";
5357 run_command
($cmd, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
5361 alarm($oldtimeout) if $oldtimeout;
5364 foreach my $devname (keys %$devinfo) {
5365 my $volid = $devinfo->{$devname}->{volid
};
5366 push @$vollist, $volid if $volid;
5369 my $cfg = PVE
::Storage
::config
();
5370 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
5378 foreach my $devname (keys %$devinfo) {
5379 my $volid = $devinfo->{$devname}->{volid
};
5382 if ($volid =~ m
|^/|) {
5383 unlink $volid || die 'unlink failed\n';
5385 PVE
::Storage
::vdisk_free
($cfg, $volid);
5387 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5389 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5396 rename($tmpfn, $conffile) ||
5397 die "unable to commit configuration file '$conffile'\n";
5399 PVE
::Cluster
::cfs_update
(); # make sure we read new file
5401 eval { rescan
($vmid, 1); };
5405 sub restore_tar_archive
{
5406 my ($archive, $vmid, $user, $opts) = @_;
5408 if ($archive ne '-') {
5409 my $firstfile = tar_archive_read_firstfile
($archive);
5410 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
5411 if $firstfile ne 'qemu-server.conf';
5414 my $storecfg = PVE
::Storage
::config
();
5416 # destroy existing data - keep empty config
5417 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
5418 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
5420 my $tocmd = "/usr/lib/qemu-server/qmextract";
5422 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
5423 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
5424 $tocmd .= ' --prealloc' if $opts->{prealloc
};
5425 $tocmd .= ' --info' if $opts->{info
};
5427 # tar option "xf" does not autodetect compression when read from STDIN,
5428 # so we pipe to zcat
5429 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
5430 PVE
::Tools
::shellquote
("--to-command=$tocmd");
5432 my $tmpdir = "/var/tmp/vzdumptmp$$";
5435 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
5436 local $ENV{VZDUMP_VMID
} = $vmid;
5437 local $ENV{VZDUMP_USER
} = $user;
5439 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5440 my $tmpfn = "$conffile.$$.tmp";
5442 # disable interrupts (always do cleanups)
5443 local $SIG{INT
} = $SIG{TERM
} = $SIG{QUIT
} = $SIG{HUP
} = sub {
5444 print STDERR
"got interrupt - ignored\n";
5449 local $SIG{INT
} = $SIG{TERM
} = $SIG{QUIT
} = $SIG{HUP
} = $SIG{PIPE
} = sub {
5450 die "interrupted by signal\n";
5453 if ($archive eq '-') {
5454 print "extracting archive from STDIN\n";
5455 run_command
($cmd, input
=> "<&STDIN");
5457 print "extracting archive '$archive'\n";
5461 return if $opts->{info
};
5465 my $statfile = "$tmpdir/qmrestore.stat";
5466 if (my $fd = IO
::File-
>new($statfile, "r")) {
5467 while (defined (my $line = <$fd>)) {
5468 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5469 $map->{$1} = $2 if $1;
5471 print STDERR
"unable to parse line in statfile - $line\n";
5477 my $confsrc = "$tmpdir/qemu-server.conf";
5479 my $srcfd = new IO
::File
($confsrc, "r") ||
5480 die "unable to open file '$confsrc'\n";
5482 my $outfd = new IO
::File
($tmpfn, "w") ||
5483 die "unable to write config for VM $vmid\n";
5485 my $cookie = { netcount
=> 0 };
5486 while (defined (my $line = <$srcfd>)) {
5487 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
5499 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
5506 rename $tmpfn, $conffile ||
5507 die "unable to commit configuration file '$conffile'\n";
5509 PVE
::Cluster
::cfs_update
(); # make sure we read new file
5511 eval { rescan
($vmid, 1); };
5515 sub foreach_writable_storage
{
5516 my ($conf, $func) = @_;
5520 foreach my $ds (keys %$conf) {
5521 next if !is_valid_drivename
($ds);
5523 my $drive = parse_drive
($ds, $conf->{$ds});
5525 next if drive_is_cdrom
($drive);
5527 my $volid = $drive->{file
};
5529 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
5530 $sidhash->{$sid} = $sid if $sid;
5533 foreach my $sid (sort keys %$sidhash) {
5538 sub do_snapshots_with_qemu
{
5539 my ($storecfg, $volid) = @_;
5541 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
5543 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
5544 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
5548 if ($volid =~ m/\.(qcow2|qed)$/){
5555 sub qga_check_running
{
5558 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
5560 warn "Qemu Guest Agent are not running - $@";
5566 sub template_create
{
5567 my ($vmid, $conf, $disk) = @_;
5569 my $storecfg = PVE
::Storage
::config
();
5571 foreach_drive
($conf, sub {
5572 my ($ds, $drive) = @_;
5574 return if drive_is_cdrom
($drive);
5575 return if $disk && $ds ne $disk;
5577 my $volid = $drive->{file
};
5578 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
5580 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
5581 $drive->{file
} = $voliddst;
5582 $conf->{$ds} = print_drive
($vmid, $drive);
5583 PVE
::QemuConfig-
>write_config($vmid, $conf);
5587 sub qemu_img_convert
{
5588 my ($src_volid, $dst_volid, $size, $snapname, $is_zero_initialized) = @_;
5590 my $storecfg = PVE
::Storage
::config
();
5591 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
5592 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
5594 if ($src_storeid && $dst_storeid) {
5596 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
5598 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
5599 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
5601 my $src_format = qemu_img_format
($src_scfg, $src_volname);
5602 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
5604 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
5605 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
5608 push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
5609 push @$cmd, '-s', $snapname if($snapname && $src_format eq "qcow2");
5610 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path;
5611 if ($is_zero_initialized) {
5612 push @$cmd, "zeroinit:$dst_path";
5614 push @$cmd, $dst_path;
5619 if($line =~ m/\((\S+)\/100\
%\)/){
5621 my $transferred = int($size * $percent / 100);
5622 my $remaining = $size - $transferred;
5624 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
5629 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
5631 die "copy failed: $err" if $err;
5635 sub qemu_img_format
{
5636 my ($scfg, $volname) = @_;
5638 if ($scfg->{path
} && $volname =~ m/\.(raw|cow|qcow|qcow2|qed|vmdk|cloop)$/) {
5645 sub qemu_drive_mirror
{
5646 my ($vmid, $drive, $dst_volid, $vmiddst, $is_zero_initialized) = @_;
5648 my $storecfg = PVE
::Storage
::config
();
5649 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
5651 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
5653 my $format = qemu_img_format
($dst_scfg, $dst_volname);
5655 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
5657 my $qemu_target = $is_zero_initialized ?
"zeroinit:$dst_path" : $dst_path;
5659 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $qemu_target };
5660 $opts->{format
} = $format if $format;
5662 print "drive mirror is starting (scanning bitmap) : this step can take some minutes/hours, depend of disk size and storage speed\n";
5664 my $finish_job = sub {
5666 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
5667 my $stat = @$stats[0];
5674 vm_mon_cmd
($vmid, "drive-mirror", %$opts);
5676 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
5677 my $stat = @$stats[0];
5678 die "mirroring job seem to have die. Maybe do you have bad sectors?" if !$stat;
5679 die "error job is not mirroring" if $stat->{type
} ne "mirror";
5681 my $busy = $stat->{busy
};
5682 my $ready = $stat->{ready
};
5684 if (my $total = $stat->{len
}) {
5685 my $transferred = $stat->{offset
} || 0;
5686 my $remaining = $total - $transferred;
5687 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
5689 print "transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
5693 if ($stat->{ready
} eq 'true') {
5695 last if $vmiddst != $vmid;
5697 # try to switch the disk if source and destination are on the same guest
5698 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> "drive-$drive") };
5703 die $@ if $@ !~ m/cannot be completed/;
5712 my $cancel_job = sub {
5713 vm_mon_cmd
($vmid, "block-job-cancel", device
=> "drive-$drive");
5718 eval { &$cancel_job(); };
5719 die "mirroring error: $err";
5722 if ($vmiddst != $vmid) {
5723 # if we clone a disk for a new target vm, we don't switch the disk
5724 &$cancel_job(); # so we call block-job-cancel
5729 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
5730 $newvmid, $storage, $format, $full, $newvollist) = @_;
5735 print "create linked clone of drive $drivename ($drive->{file})\n";
5736 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
5737 push @$newvollist, $newvolid;
5739 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
5740 $storeid = $storage if $storage;
5742 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
5744 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
5745 $format = qemu_img_format
($scfg, $volname);
5748 # test if requested format is supported - else use default
5749 my $supported = grep { $_ eq $format } @$validFormats;
5750 $format = $defFormat if !$supported;
5752 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
5754 print "create full clone of drive $drivename ($drive->{file})\n";
5755 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $format, undef, ($size/1024));
5756 push @$newvollist, $newvolid;
5758 PVE
::Storage
::activate_volumes
($storecfg, [$newvolid]);
5760 my $sparseinit = PVE
::Storage
::volume_has_feature
($storecfg, 'sparseinit', $newvolid);
5761 if (!$running || $snapname) {
5762 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname, $sparseinit);
5764 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid, $sparseinit);
5768 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
5771 $disk->{format
} = undef;
5772 $disk->{file
} = $newvolid;
5773 $disk->{size
} = $size;
5778 # this only works if VM is running
5779 sub get_current_qemu_machine
{
5782 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
5783 my $res = vm_qmp_command
($vmid, $cmd);
5785 my ($current, $default);
5786 foreach my $e (@$res) {
5787 $default = $e->{name
} if $e->{'is-default'};
5788 $current = $e->{name
} if $e->{'is-current'};
5791 # fallback to the default machine if current is not supported by qemu
5792 return $current || $default || 'pc';
5795 sub qemu_machine_feature_enabled
{
5796 my ($machine, $kvmver, $version_major, $version_minor) = @_;
5801 if ($machine && $machine =~ m/^(pc(-i440fx|-q35)?-(\d+)\.(\d+))/) {
5803 $current_major = $3;
5804 $current_minor = $4;
5806 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
5808 $current_major = $1;
5809 $current_minor = $2;
5812 return 1 if $current_major >= $version_major && $current_minor >= $version_minor;
5817 sub qemu_machine_pxe
{
5818 my ($vmid, $conf, $machine) = @_;
5820 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
5822 foreach my $opt (keys %$conf) {
5823 next if $opt !~ m/^net(\d+)$/;
5824 my $net = PVE
::QemuServer
::parse_net
($conf->{$opt});
5826 my $romfile = PVE
::QemuServer
::vm_mon_cmd_nocheck
($vmid, 'qom-get', path
=> $opt, property
=> 'romfile');
5827 return $machine.".pxe" if $romfile =~ m/pxe/;
5834 sub qemu_use_old_bios_files
{
5835 my ($machine_type) = @_;
5837 return if !$machine_type;
5839 my $use_old_bios_files = undef;
5841 if ($machine_type =~ m/^(\S+)\.pxe$/) {
5843 $use_old_bios_files = 1;
5845 my $kvmver = kvm_user_version
();
5846 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
5847 # load new efi bios files on migration. So this hack is required to allow
5848 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
5849 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
5850 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
5853 return ($use_old_bios_files, $machine_type);
5860 dir_glob_foreach
("$pcisysfs/devices", '[a-f0-9]{4}:([a-f0-9]{2}:[a-f0-9]{2})\.([0-9])', sub {
5861 my (undef, $id, $function) = @_;
5862 my $res = { id
=> $id, function
=> $function};
5863 push @{$devices->{$id}}, $res;
5869 sub vm_iothreads_list
{
5872 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
5875 foreach my $iothread (@$res) {
5876 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
5883 my ($conf, $drive) = @_;
5887 if ($conf->{scsihw
} && ($conf->{scsihw
} =~ m/^lsi/)) {
5889 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
5895 my $controller = int($drive->{index} / $maxdev);
5896 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
5898 return ($maxdev, $controller, $controller_prefix);
5901 # bash completion helper
5903 sub complete_backup_archives
{
5904 my ($cmdname, $pname, $cvalue) = @_;
5906 my $cfg = PVE
::Storage
::config
();
5910 if ($cvalue =~ m/^([^:]+):/) {
5914 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
5917 foreach my $id (keys %$data) {
5918 foreach my $item (@{$data->{$id}}) {
5919 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
5920 push @$res, $item->{volid
} if defined($item->{volid
});
5927 my $complete_vmid_full = sub {
5930 my $idlist = vmstatus
();
5934 foreach my $id (keys %$idlist) {
5935 my $d = $idlist->{$id};
5936 if (defined($running)) {
5937 next if $d->{template
};
5938 next if $running && $d->{status
} ne 'running';
5939 next if !$running && $d->{status
} eq 'running';
5948 return &$complete_vmid_full();
5951 sub complete_vmid_stopped
{
5952 return &$complete_vmid_full(0);
5955 sub complete_vmid_running
{
5956 return &$complete_vmid_full(1);
5959 sub complete_storage
{
5961 my $cfg = PVE
::Storage
::config
();
5962 my $ids = $cfg->{ids
};
5965 foreach my $sid (keys %$ids) {
5966 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
5967 next if !$ids->{$sid}->{content
}->{images
};