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 Time
::HiRes
qw(gettimeofday);
34 use File
::Copy
qw(copy);
36 my $qemu_snap_storage = {rbd
=> 1, sheepdog
=> 1};
38 my $cpuinfo = PVE
::ProcFSTools
::read_cpuinfo
();
40 # Note about locking: we use flock on the config file protect
41 # against concurent actions.
42 # Aditionaly, we have a 'lock' setting in the config file. This
43 # can be set to 'migrate', 'backup', 'snapshot' or 'rollback'. Most actions are not
44 # allowed when such lock is set. But you can ignore this kind of
45 # lock with the --skiplock flag.
47 cfs_register_file
('/qemu-server/',
51 PVE
::JSONSchema
::register_standard_option
('skiplock', {
52 description
=> "Ignore locks - only root is allowed to use this option.",
57 PVE
::JSONSchema
::register_standard_option
('pve-qm-stateuri', {
58 description
=> "Some command save/restore state from this location.",
64 PVE
::JSONSchema
::register_standard_option
('pve-snapshot-name', {
65 description
=> "The name of the snapshot.",
66 type
=> 'string', format
=> 'pve-configid',
70 #no warnings 'redefine';
73 my ($controller, $vmid, $option, $value) = @_;
75 my $path = "/sys/fs/cgroup/$controller/qemu.slice/$vmid.scope/$option";
76 PVE
::ProcFSTools
::write_proc_entry
($path, $value);
80 my $nodename = PVE
::INotify
::nodename
();
82 mkdir "/etc/pve/nodes/$nodename";
83 my $confdir = "/etc/pve/nodes/$nodename/qemu-server";
86 my $var_run_tmpdir = "/var/run/qemu-server";
87 mkdir $var_run_tmpdir;
89 my $lock_dir = "/var/lock/qemu-server";
92 my $pcisysfs = "/sys/bus/pci";
96 description
=> "Emulated CPU type.",
98 enum
=> [ qw(486 athlon pentium pentium2 pentium3 coreduo core2duo kvm32 kvm64 qemu32 qemu64 phenom Conroe Penryn Nehalem Westmere SandyBridge IvyBridge Haswell Haswell-noTSX Broadwell Broadwell-noTSX Opteron_G1 Opteron_G2 Opteron_G3 Opteron_G4 Opteron_G5 host) ],
103 description
=> "Do not identify as a KVM virtual machine.",
114 description
=> "Specifies whether a VM will be started during system bootup.",
120 description
=> "Automatic restart after crash (currently ignored).",
125 type
=> 'string', format
=> 'pve-hotplug-features',
126 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'.",
127 default => 'network,disk,usb',
132 description
=> "Allow reboot. If set to '0' the VM exit on reboot.",
138 description
=> "Lock/unlock the VM.",
139 enum
=> [qw(migrate backup snapshot rollback)],
144 description
=> "Limit of CPU usage. Note if the computer has 2 CPUs, it has total of '2' CPU time. Value '0' indicates no CPU limit.",
152 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.",
160 description
=> "Amount of RAM for the VM in MB. This is the maximum available memory when you use the balloon device.",
167 description
=> "Amount of target RAM for the VM in MB. Using zero disables the ballon driver.",
173 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",
181 description
=> "Keybord layout for vnc server. Default is read from the datacenter configuration file.",
182 enum
=> PVE
::Tools
::kvmkeymaplist
(),
187 type
=> 'string', format
=> 'dns-name',
188 description
=> "Set a name for the VM. Only used on the configuration web interface.",
193 description
=> "scsi controller model",
194 enum
=> [qw(lsi lsi53c810 virtio-scsi-pci virtio-scsi-single megasas pvscsi)],
200 description
=> "Description for the VM. Only used on the configuration web interface. This is saved as comment inside the configuration file.",
205 enum
=> [qw(other wxp w2k w2k3 w2k8 wvista win7 win8 l24 l26 solaris)],
206 description
=> <<EODESC,
207 Used to enable special optimization/features for specific
210 other => unspecified OS
211 wxp => Microsoft Windows XP
212 w2k => Microsoft Windows 2000
213 w2k3 => Microsoft Windows 2003
214 w2k8 => Microsoft Windows 2008
215 wvista => Microsoft Windows Vista
216 win7 => Microsoft Windows 7
217 win8 => Microsoft Windows 8/2012
218 l24 => Linux 2.4 Kernel
219 l26 => Linux 2.6/3.X Kernel
220 solaris => solaris/opensolaris/openindiania kernel
222 other|l24|l26|solaris ... no special behaviour
223 wxp|w2k|w2k3|w2k8|wvista|win7|win8 ... use --localtime switch
229 description
=> "Boot on floppy (a), hard disk (c), CD-ROM (d), or network (n).",
230 pattern
=> '[acdn]{1,4}',
235 type
=> 'string', format
=> 'pve-qm-bootdisk',
236 description
=> "Enable booting from specified disk.",
237 pattern
=> '(ide|sata|scsi|virtio)\d+',
242 description
=> "The number of CPUs. Please use option -sockets instead.",
249 description
=> "The number of CPU sockets.",
256 description
=> "The number of cores per socket.",
263 description
=> "Enable/disable NUMA.",
269 description
=> "Number of hotplugged vcpus.",
276 description
=> "Enable/disable ACPI.",
282 description
=> "Enable/disable Qemu GuestAgent.",
288 description
=> "Enable/disable KVM hardware virtualization.",
294 description
=> "Enable/disable time drift fix.",
300 description
=> "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
305 description
=> "Freeze CPU at startup (use 'c' monitor command to start execution).",
310 description
=> "Select the VGA type. If you want to use high resolution" .
311 " modes (>= 1280x1024x16) then you should use the options " .
312 "'std' or 'vmware'. Default is 'std' for win8/win7/w2k8, and " .
313 "'cirrus' for other OS types. The 'qxl' option enables the SPICE " .
314 "display sever. For win* OS you can select how many independent " .
315 "displays you want, Linux guests can add displays them self. " .
316 "You can also run without any graphic card, using a serial device" .
318 enum
=> [qw(std cirrus vmware qxl serial0 serial1 serial2 serial3 qxl2 qxl3 qxl4)],
322 type
=> 'string', format
=> 'pve-qm-watchdog',
323 typetext
=> '[[model=]i6300esb|ib700] [,[action=]reset|shutdown|poweroff|pause|debug|none]',
324 description
=> "Create a virtual hardware watchdog device. Once enabled" .
325 " (by a guest action), the watchdog must be periodically polled " .
326 "by an agent inside the guest or else the watchdog will reset " .
327 "the guest (or execute the respective action specified)",
332 typetext
=> "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
333 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'.",
334 pattern
=> '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
337 startup
=> get_standard_option
('pve-startup-order'),
341 description
=> "Enable/disable Template.",
347 description
=> <<EODESCR,
348 Note: this option is for experts only. It allows you to pass arbitrary arguments to kvm, for example:
350 args: -no-reboot -no-hpet
357 description
=> "Enable/disable the USB tablet device. This device is " .
358 "usually needed to allow absolute mouse positioning with VNC. " .
359 "Else the mouse runs out of sync with normal VNC clients. " .
360 "If you're running lots of console-only guests on one host, " .
361 "you may consider disabling this to save some context switches. " .
362 "This is turned off by default if you use spice (-vga=qxl).",
367 description
=> "Set maximum speed (in MB/s) for migrations. Value 0 is no limit.",
371 migrate_downtime
=> {
374 description
=> "Set maximum tolerated downtime (in seconds) for migrations.",
380 type
=> 'string', format
=> 'pve-qm-drive',
381 typetext
=> 'volume',
382 description
=> "This is an alias for option -ide2",
386 description
=> "Emulated CPU type.",
390 parent
=> get_standard_option
('pve-snapshot-name', {
392 description
=> "Parent snapshot name. This is used internally, and should not be modified.",
396 description
=> "Timestamp for snapshots.",
402 type
=> 'string', format
=> 'pve-volume-id',
403 description
=> "Reference to a volume which stores the VM state. This is used internally for snapshots.",
406 description
=> "Specific the Qemu machine type.",
408 pattern
=> '(pc|pc(-i440fx)?-\d+\.\d+(\.pxe)?|q35|pc-q35-\d+\.\d+(\.pxe)?)',
413 description
=> "Specify SMBIOS type 1 fields.",
414 type
=> 'string', format
=> 'pve-qm-smbios1',
421 description
=> "Sets the protection flag of the VM. This will prevent the remove operation.",
427 enum
=> [ qw(seabios ovmf) ],
428 description
=> "Select BIOS implementation.",
429 default => 'seabios',
433 # what about other qemu settings ?
435 #machine => 'string',
448 ##soundhw => 'string',
450 while (my ($k, $v) = each %$confdesc) {
451 PVE
::JSONSchema
::register_standard_option
("pve-qm-$k", $v);
454 my $MAX_IDE_DISKS = 4;
455 my $MAX_SCSI_DISKS = 14;
456 my $MAX_VIRTIO_DISKS = 16;
457 my $MAX_SATA_DISKS = 6;
458 my $MAX_USB_DEVICES = 5;
460 my $MAX_UNUSED_DISKS = 8;
461 my $MAX_HOSTPCI_DEVICES = 4;
462 my $MAX_SERIAL_PORTS = 4;
463 my $MAX_PARALLEL_PORTS = 3;
465 my $MAX_MEM = 4194304;
466 my $STATICMEM = 1024;
470 type
=> 'string', format
=> 'pve-qm-numanode',
471 typetext
=> "cpus=<id[-id],memory=<mb>[[,hostnodes=<id[-id]>] [,policy=<preferred|bind|interleave>]]",
472 description
=> "numa topology",
474 PVE
::JSONSchema
::register_standard_option
("pve-qm-numanode", $numadesc);
476 for (my $i = 0; $i < $MAX_NUMA; $i++) {
477 $confdesc->{"numa$i"} = $numadesc;
480 my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000', 'pcnet', 'virtio',
481 'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
482 'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
483 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
487 type
=> 'string', format
=> 'pve-qm-net',
488 typetext
=> "MODEL=XX:XX:XX:XX:XX:XX [,bridge=<dev>][,queues=<nbqueues>][,rate=<mbps>] [,tag=<vlanid>][,trunks=<vlanid[;vlanid]>][,firewall=0|1],link_down=0|1]",
489 description
=> <<EODESCR,
490 Specify network devices.
492 MODEL is one of: $nic_model_list_txt
494 XX:XX:XX:XX:XX:XX should be an unique MAC address. This is
495 automatically generated if not specified.
497 The bridge parameter can be used to automatically add the interface to a bridge device. The Proxmox VE standard bridge is called 'vmbr0'.
499 Option 'rate' is used to limit traffic bandwidth from and to this interface. It is specified as floating point number, unit is 'Megabytes per second'.
501 If you specify no bridge, we create a kvm 'user' (NATed) network device, which provides DHCP and DNS services. The following addresses are used:
507 The DHCP server assign addresses to the guest starting from 10.0.2.15.
511 PVE
::JSONSchema
::register_standard_option
("pve-qm-net", $netdesc);
513 for (my $i = 0; $i < $MAX_NETS; $i++) {
514 $confdesc->{"net$i"} = $netdesc;
519 my %drivedesc_base = (
520 volume
=> { alias
=> 'file' },
522 type
=> 'pve-volume-id',
524 format_description
=> 'volume',
525 description
=> "The drive's backing volume.",
529 format_description
=> 'cdrom|disk',
530 enum
=> [qw(cdrom disk)],
531 description
=> "The drive's media type.",
537 format_description
=> 'count',
538 description
=> "Force the drive's physical geometry to have a specific cylinder count.",
543 format_description
=> 'count',
544 description
=> "Force the drive's physical geometry to have a specific head count.",
549 format_description
=> 'count',
550 description
=> "Force the drive's physical geometry to have a specific sector count.",
555 format_description
=> 'none|lba|auto',
556 enum
=> [qw(none lba auto)],
557 description
=> "Force disk geometry bios translation mode.",
562 format_description
=> 'on|off',
563 description
=> "Whether the drive should be included when making snapshots.",
568 format_description
=> 'none|writethrough|writeback|unsafe|directsync',
569 enum
=> [qw(none writethrough writeback unsafe directsync)],
570 description
=> "The drive's cache mode",
575 format_description
=> 'drive format',
576 enum
=> [qw(raw cow qcow qed qcow2 vmdk cloop)],
577 description
=> "The drive's backing file's data format.",
582 format
=> 'disk-size',
583 description
=> "Disk size. This is purely informational and has no effect.",
588 format_description
=> 'on|off',
589 description
=> "Whether the drive should be included when making backups.",
594 format_description
=> 'enospc|ignore|report|stop',
595 enum
=> [qw(enospc ignore report stop)],
596 description
=> 'Write error action.',
601 format_description
=> 'native|threads',
602 enum
=> [qw(native threads)],
603 description
=> 'AIO type to use.',
608 format_description
=> 'ignore|on',
609 enum
=> [qw(ignore on)],
610 description
=> 'Controls whether to pass discard/trim requests to the underlying storage.',
615 description
=> 'Controls whether to detect and try to optimize writes of zeroes.',
620 format_description
=> 'serial',
621 description
=> "The drive's reported serial number.",
629 format_description
=> 'ignore|report|stop',
630 enum
=> [qw(ignore report stop)],
631 description
=> 'Read error action.',
636 my %iothread_fmt = ( iothread
=> {
638 format_description
=> 'off|on',
639 description
=> "Whether to use iothreads for this drive",
646 format_description
=> 'model',
647 description
=> "The drive's reported model name.",
655 format_description
=> 'nbqueues',
656 description
=> "Number of queues.",
662 my $add_throttle_desc = sub {
663 my ($key, $type, $what, $size, $longsize) = @_;
664 $drivedesc_base{$key} = {
666 format_description
=> $size,
667 description
=> "Maximum $what speed in $longsize per second.",
671 # throughput: (leaky bucket)
672 $add_throttle_desc->('bps', 'integer', 'r/w speed', 'bps', 'bytes');
673 $add_throttle_desc->('bps_rd', 'integer', 'read speed', 'bps', 'bytes');
674 $add_throttle_desc->('bps_wr', 'integer', 'write speed', 'bps', 'bytes');
675 $add_throttle_desc->('mbps', 'float', 'r/w speed', 'mbps', 'megabytes');
676 $add_throttle_desc->('mbps_rd', 'float', 'read speed', 'mbps', 'megabytes');
677 $add_throttle_desc->('mbps_wr', 'float', 'write speed', 'mbps', 'megabytes');
678 $add_throttle_desc->('iops', 'integer', 'r/w I/O', 'iops', 'operations');
679 $add_throttle_desc->('iops_rd', 'integer', 'read I/O', 'iops', 'operations');
680 $add_throttle_desc->('iops_wr', 'integer', 'write I/O', 'iops', 'operations');
682 # pools: (pool of IO before throttling starts taking effect)
683 $add_throttle_desc->('mbps_max', 'float', 'unthrottled r/w pool', 'mbps', 'megabytes');
684 $add_throttle_desc->('mbps_rd_max', 'float', 'unthrottled read pool', 'mbps', 'megabytes');
685 $add_throttle_desc->('mbps_wr_max', 'float', 'unthrottled write pool', 'mbps', 'megabytes');
686 $add_throttle_desc->('iops_max', 'integer', 'unthrottled r/w I/O pool', 'iops', 'operations');
687 $add_throttle_desc->('iops_rd_max', 'integer', 'unthrottled read I/O pool', 'iops', 'operations');
688 $add_throttle_desc->('iops_wr_max', 'integer', 'unthrottled write I/O pool', 'iops', 'operations');
698 type
=> 'string', format
=> $ide_fmt,
699 description
=> "Use volume as IDE hard disk or CD-ROM (n is 0 to " .($MAX_IDE_DISKS -1) . ").",
701 PVE
::JSONSchema
::register_standard_option
("pve-qm-ide", $idedesc);
710 type
=> 'string', format
=> $scsi_fmt,
711 description
=> "Use volume as SCSI hard disk or CD-ROM (n is 0 to " . ($MAX_SCSI_DISKS - 1) . ").",
713 PVE
::JSONSchema
::register_standard_option
("pve-qm-scsi", $scsidesc);
721 type
=> 'string', format
=> $sata_fmt,
722 description
=> "Use volume as SATA hard disk or CD-ROM (n is 0 to " . ($MAX_SATA_DISKS - 1). ").",
724 PVE
::JSONSchema
::register_standard_option
("pve-qm-sata", $satadesc);
733 type
=> 'string', format
=> $virtio_fmt,
734 description
=> "Use volume as VIRTIO hard disk (n is 0 to " . ($MAX_VIRTIO_DISKS - 1) . ").",
736 PVE
::JSONSchema
::register_standard_option
("pve-qm-virtio", $virtiodesc);
749 type
=> 'string', format
=> 'pve-qm-usb-device',
750 format_description
=> 'HOSTUSBDEVICE|spice',
751 description
=> 'The Host USB device or port or the value spice',
756 format_description
=> 'yes|no',
757 description
=> 'Specifies whether if given host option is a USB3 device or port',
763 type
=> 'string', format
=> $usbformat,
764 description
=> <<EODESCR,
765 Configure an USB device (n is 0 to 4). This can be used to
766 pass-through usb devices to the guest. HOSTUSBDEVICE syntax is:
768 'bus-port(.port)*' (decimal numbers) or
769 'vendor_id:product_id' (hexadeciaml numbers) or
772 You can use the 'lsusb -t' command to list existing usb devices.
774 Note: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
776 The value 'spice' can be used to add a usb redirection devices for spice.
778 The 'usb3' option determines whether the device is a USB3 device or not (this does currently not work reliably with spice redirection and is then ignored).
782 PVE
::JSONSchema
::register_standard_option
("pve-qm-usb", $usbdesc);
786 type
=> 'string', format
=> 'pve-qm-hostpci',
787 typetext
=> "[host=]HOSTPCIDEVICE [,rombar=on|off] [,pcie=0|1] [,x-vga=on|off]",
788 description
=> <<EODESCR,
789 Map host pci devices. HOSTPCIDEVICE syntax is:
791 'bus:dev.func' (hexadecimal numbers)
793 You can us the 'lspci' command to list existing pci devices.
795 The 'rombar' option determines whether or not the device's ROM will be visible in the guest's memory map (default is 'on').
797 Note: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
799 Experimental: user reported problems with this option.
802 PVE
::JSONSchema
::register_standard_option
("pve-qm-hostpci", $hostpcidesc);
807 pattern
=> '(/dev/.+|socket)',
808 description
=> <<EODESCR,
809 Create a serial device inside the VM (n is 0 to 3), and pass through a host serial device (i.e. /dev/ttyS0), or create a unix socket on the host side (use 'qm terminal' to open a terminal connection).
811 Note: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
813 Experimental: user reported problems with this option.
820 pattern
=> '/dev/parport\d+|/dev/usb/lp\d+',
821 description
=> <<EODESCR,
822 Map host parallel devices (n is 0 to 2).
824 Note: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
826 Experimental: user reported problems with this option.
830 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
831 $confdesc->{"parallel$i"} = $paralleldesc;
834 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
835 $confdesc->{"serial$i"} = $serialdesc;
838 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
839 $confdesc->{"hostpci$i"} = $hostpcidesc;
842 for (my $i = 0; $i < $MAX_IDE_DISKS; $i++) {
843 $drivename_hash->{"ide$i"} = 1;
844 $confdesc->{"ide$i"} = $idedesc;
847 for (my $i = 0; $i < $MAX_SATA_DISKS; $i++) {
848 $drivename_hash->{"sata$i"} = 1;
849 $confdesc->{"sata$i"} = $satadesc;
852 for (my $i = 0; $i < $MAX_SCSI_DISKS; $i++) {
853 $drivename_hash->{"scsi$i"} = 1;
854 $confdesc->{"scsi$i"} = $scsidesc ;
857 for (my $i = 0; $i < $MAX_VIRTIO_DISKS; $i++) {
858 $drivename_hash->{"virtio$i"} = 1;
859 $confdesc->{"virtio$i"} = $virtiodesc;
862 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
863 $confdesc->{"usb$i"} = $usbdesc;
868 type
=> 'string', format
=> 'pve-volume-id',
869 description
=> "Reference to unused volumes.",
872 for (my $i = 0; $i < $MAX_UNUSED_DISKS; $i++) {
873 $confdesc->{"unused$i"} = $unuseddesc;
876 my $kvm_api_version = 0;
880 return $kvm_api_version if $kvm_api_version;
882 my $fh = IO
::File-
>new("</dev/kvm") ||
885 if (my $v = $fh->ioctl(KVM_GET_API_VERSION
(), 0)) {
886 $kvm_api_version = $v;
891 return $kvm_api_version;
894 my $kvm_user_version;
896 sub kvm_user_version
{
898 return $kvm_user_version if $kvm_user_version;
900 $kvm_user_version = 'unknown';
904 if ($line =~ m/^QEMU( PC)? emulator version (\d+\.\d+(\.\d+)?)(\.\d+)?[,\s]/) {
905 $kvm_user_version = $2;
909 eval { run_command
("kvm -version", outfunc
=> $code); };
912 return $kvm_user_version;
916 my $kernel_has_vhost_net = -c
'/dev/vhost-net';
918 sub valid_drive_names
{
919 # order is important - used to autoselect boot disk
920 return ((map { "ide$_" } (0 .. ($MAX_IDE_DISKS - 1))),
921 (map { "scsi$_" } (0 .. ($MAX_SCSI_DISKS - 1))),
922 (map { "virtio$_" } (0 .. ($MAX_VIRTIO_DISKS - 1))),
923 (map { "sata$_" } (0 .. ($MAX_SATA_DISKS - 1))));
926 sub is_valid_drivename
{
929 return defined($drivename_hash->{$dev});
934 return defined($confdesc->{$key});
938 return $nic_model_list;
941 sub os_list_description
{
946 w2k
=> 'Windows 2000',
947 w2k3
=>, 'Windows 2003',
948 w2k8
=> 'Windows 2008',
949 wvista
=> 'Windows Vista',
951 win8
=> 'Windows 8/2012',
961 return $cdrom_path if $cdrom_path;
963 return $cdrom_path = "/dev/cdrom" if -l
"/dev/cdrom";
964 return $cdrom_path = "/dev/cdrom1" if -l
"/dev/cdrom1";
965 return $cdrom_path = "/dev/cdrom2" if -l
"/dev/cdrom2";
969 my ($storecfg, $vmid, $cdrom) = @_;
971 if ($cdrom eq 'cdrom') {
972 return get_cdrom_path
();
973 } elsif ($cdrom eq 'none') {
975 } elsif ($cdrom =~ m
|^/|) {
978 return PVE
::Storage
::path
($storecfg, $cdrom);
982 # try to convert old style file names to volume IDs
983 sub filename_to_volume_id
{
984 my ($vmid, $file, $media) = @_;
986 if (!($file eq 'none' || $file eq 'cdrom' ||
987 $file =~ m
|^/dev/.+| || $file =~ m/^([^:]+):(.+)$/)) {
989 return undef if $file =~ m
|/|;
991 if ($media && $media eq 'cdrom') {
992 $file = "local:iso/$file";
994 $file = "local:$vmid/$file";
1001 sub verify_media_type
{
1002 my ($opt, $vtype, $media) = @_;
1007 if ($media eq 'disk') {
1009 } elsif ($media eq 'cdrom') {
1012 die "internal error";
1015 return if ($vtype eq $etype);
1017 raise_param_exc
({ $opt => "unexpected media type ($vtype != $etype)" });
1020 sub cleanup_drive_path
{
1021 my ($opt, $storecfg, $drive) = @_;
1023 # try to convert filesystem paths to volume IDs
1025 if (($drive->{file
} !~ m/^(cdrom|none)$/) &&
1026 ($drive->{file
} !~ m
|^/dev/.+|) &&
1027 ($drive->{file
} !~ m/^([^:]+):(.+)$/) &&
1028 ($drive->{file
} !~ m/^\d+$/)) {
1029 my ($vtype, $volid) = PVE
::Storage
::path_to_volume_id
($storecfg, $drive->{file
});
1030 raise_param_exc
({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
1031 $drive->{media
} = 'cdrom' if !$drive->{media
} && $vtype eq 'iso';
1032 verify_media_type
($opt, $vtype, $drive->{media
});
1033 $drive->{file
} = $volid;
1036 $drive->{media
} = 'cdrom' if !$drive->{media
} && $drive->{file
} =~ m/^(cdrom|none)$/;
1039 sub parse_hotplug_features
{
1044 return $res if $data eq '0';
1046 $data = $confdesc->{hotplug
}->{default} if $data eq '1';
1048 foreach my $feature (PVE
::Tools
::split_list
($data)) {
1049 if ($feature =~ m/^(network|disk|cpu|memory|usb)$/) {
1052 warn "ignoring unknown hotplug feature '$feature'\n";
1058 PVE
::JSONSchema
::register_format
('pve-hotplug-features', \
&pve_verify_hotplug_features
);
1059 sub pve_verify_hotplug_features
{
1060 my ($value, $noerr) = @_;
1062 return $value if parse_hotplug_features
($value);
1064 return undef if $noerr;
1066 die "unable to parse hotplug option\n";
1069 # ideX = [volume=]volume-id[,media=d][,cyls=c,heads=h,secs=s[,trans=t]]
1070 # [,snapshot=on|off][,cache=on|off][,format=f][,backup=yes|no]
1071 # [,rerror=ignore|report|stop][,werror=enospc|ignore|report|stop]
1072 # [,aio=native|threads][,discard=ignore|on][,detect_zeroes=on|off]
1073 # [,iothread=on][,serial=serial][,model=model]
1076 my ($key, $data) = @_;
1078 my ($interface, $index);
1080 if ($key =~ m/^([^\d]+)(\d+)$/) {
1087 my $desc = $key =~ /^unused\d+$/ ?
$alldrive_fmt
1088 : $confdesc->{$key}->{format
};
1090 warn "invalid drive key: $key\n";
1093 my $res = eval { PVE
::JSONSchema
::parse_property_string
($desc, $data) };
1094 return undef if !$res;
1095 $res->{interface
} = $interface;
1096 $res->{index} = $index;
1099 foreach my $opt (qw(bps bps_rd bps_wr)) {
1100 if (my $bps = defined(delete $res->{$opt})) {
1101 if (defined($res->{"m$opt"})) {
1102 warn "both $opt and m$opt specified\n";
1106 $res->{"m$opt"} = sprintf("%.3f", $bps / (1024*1024.0));
1109 return undef if $error;
1111 return undef if $res->{mbps_rd
} && $res->{mbps
};
1112 return undef if $res->{mbps_wr
} && $res->{mbps
};
1113 return undef if $res->{iops_rd
} && $res->{iops
};
1114 return undef if $res->{iops_wr
} && $res->{iops
};
1116 if ($res->{media
} && ($res->{media
} eq 'cdrom')) {
1117 return undef if $res->{snapshot
} || $res->{trans
} || $res->{format
};
1118 return undef if $res->{heads
} || $res->{secs
} || $res->{cyls
};
1119 return undef if $res->{interface
} eq 'virtio';
1122 if (my $size = $res->{size
}) {
1123 return undef if !defined($res->{size
} = PVE
::JSONSchema
::parse_size
($size));
1130 my ($vmid, $drive) = @_;
1131 my $data = { %$drive };
1132 delete $data->{$_} for qw(index interface);
1133 return PVE
::JSONSchema
::print_property_string
($data, $alldrive_fmt);
1137 my($fh, $noerr) = @_;
1140 my $SG_GET_VERSION_NUM = 0x2282;
1142 my $versionbuf = "\x00" x
8;
1143 my $ret = ioctl($fh, $SG_GET_VERSION_NUM, $versionbuf);
1145 die "scsi ioctl SG_GET_VERSION_NUM failoed - $!\n" if !$noerr;
1148 my $version = unpack("I", $versionbuf);
1149 if ($version < 30000) {
1150 die "scsi generic interface too old\n" if !$noerr;
1154 my $buf = "\x00" x
36;
1155 my $sensebuf = "\x00" x
8;
1156 my $cmd = pack("C x3 C x1", 0x12, 36);
1158 # see /usr/include/scsi/sg.h
1159 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";
1161 my $packet = pack($sg_io_hdr_t, ord('S'), -3, length($cmd),
1162 length($sensebuf), 0, length($buf), $buf,
1163 $cmd, $sensebuf, 6000);
1165 $ret = ioctl($fh, $SG_IO, $packet);
1167 die "scsi ioctl SG_IO failed - $!\n" if !$noerr;
1171 my @res = unpack($sg_io_hdr_t, $packet);
1172 if ($res[17] || $res[18]) {
1173 die "scsi ioctl SG_IO status error - $!\n" if !$noerr;
1178 (my $byte0, my $byte1, $res->{vendor
},
1179 $res->{product
}, $res->{revision
}) = unpack("C C x6 A8 A16 A4", $buf);
1181 $res->{removable
} = $byte1 & 128 ?
1 : 0;
1182 $res->{type
} = $byte0 & 31;
1190 my $fh = IO
::File-
>new("+<$path") || return undef;
1191 my $res = scsi_inquiry
($fh, 1);
1197 sub machine_type_is_q35
{
1200 return $conf->{machine
} && ($conf->{machine
} =~ m/q35/) ?
1 : 0;
1203 sub print_tabletdevice_full
{
1206 my $q35 = machine_type_is_q35
($conf);
1208 # we use uhci for old VMs because tablet driver was buggy in older qemu
1209 my $usbbus = $q35 ?
"ehci" : "uhci";
1211 return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
1214 sub print_drivedevice_full
{
1215 my ($storecfg, $conf, $vmid, $drive, $bridges) = @_;
1220 if ($drive->{interface
} eq 'virtio') {
1221 my $pciaddr = print_pci_addr
("$drive->{interface}$drive->{index}", $bridges);
1222 $device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
1223 $device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread
};
1224 } elsif ($drive->{interface
} eq 'scsi') {
1226 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
1227 my $unit = $drive->{index} % $maxdev;
1228 my $devicetype = 'hd';
1230 if (drive_is_cdrom
($drive)) {
1233 if ($drive->{file
} =~ m
|^/|) {
1234 $path = $drive->{file
};
1235 if (my $info = path_is_scsi
($path)) {
1236 if ($info->{type
} == 0) {
1237 $devicetype = 'block';
1238 } elsif ($info->{type
} == 1) { # tape
1239 $devicetype = 'generic';
1243 $path = PVE
::Storage
::path
($storecfg, $drive->{file
});
1246 if($path =~ m/^iscsi\:\/\
//){
1247 $devicetype = 'generic';
1251 if (!$conf->{scsihw
} || ($conf->{scsihw
} =~ m/^lsi/)){
1252 $device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1254 $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}";
1257 } elsif ($drive->{interface
} eq 'ide'){
1259 my $controller = int($drive->{index} / $maxdev);
1260 my $unit = $drive->{index} % $maxdev;
1261 my $devicetype = ($drive->{media
} && $drive->{media
} eq 'cdrom') ?
"cd" : "hd";
1263 $device = "ide-$devicetype,bus=ide.$controller,unit=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1264 if ($devicetype eq 'hd' && (my $model = $drive->{model
})) {
1265 $device .= ",model=$model";
1267 } elsif ($drive->{interface
} eq 'sata'){
1268 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
1269 my $unit = $drive->{index} % $MAX_SATA_DISKS;
1270 $device = "ide-drive,bus=ahci$controller.$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
1271 } elsif ($drive->{interface
} eq 'usb') {
1273 # -device ide-drive,bus=ide.1,unit=0,drive=drive-ide0-1-0,id=ide0-1-0
1275 die "unsupported interface type";
1278 $device .= ",bootindex=$drive->{bootindex}" if $drive->{bootindex
};
1283 sub get_initiator_name
{
1286 my $fh = IO
::File-
>new('/etc/iscsi/initiatorname.iscsi') || return undef;
1287 while (defined(my $line = <$fh>)) {
1288 next if $line !~ m/^\s*InitiatorName\s*=\s*([\.\-:\w]+)/;
1297 sub print_drive_full
{
1298 my ($storecfg, $vmid, $drive) = @_;
1301 my $volid = $drive->{file
};
1304 if (drive_is_cdrom
($drive)) {
1305 $path = get_iso_path
($storecfg, $vmid, $volid);
1307 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1309 $path = PVE
::Storage
::path
($storecfg, $volid);
1310 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1311 $format = qemu_img_format
($scfg, $volname);
1319 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 serial);
1320 foreach my $o (@qemu_drive_options) {
1321 $opts .= ",$o=$drive->{$o}" if $drive->{$o};
1324 $opts .= ",format=$format" if $format && !$drive->{format
};
1326 foreach my $o (qw(bps bps_rd bps_wr)) {
1327 my $v = $drive->{"m$o"};
1328 $opts .= ",$o=" . int($v*1024*1024) if $v;
1331 my $cache_direct = 0;
1333 if (my $cache = $drive->{cache
}) {
1334 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1335 } elsif (!drive_is_cdrom
($drive)) {
1336 $opts .= ",cache=none";
1340 # aio native works only with O_DIRECT
1341 if (!$drive->{aio
}) {
1343 $opts .= ",aio=native";
1345 $opts .= ",aio=threads";
1349 if (!drive_is_cdrom
($drive)) {
1351 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1352 $detectzeroes = 'off';
1353 } elsif ($drive->{discard
}) {
1354 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1356 # This used to be our default with discard not being specified:
1357 $detectzeroes = 'on';
1359 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1362 my $pathinfo = $path ?
"file=$path," : '';
1364 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1367 sub print_netdevice_full
{
1368 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files) = @_;
1370 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
1372 my $device = $net->{model
};
1373 if ($net->{model
} eq 'virtio') {
1374 $device = 'virtio-net-pci';
1377 my $pciaddr = print_pci_addr
("$netid", $bridges);
1378 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1379 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1380 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1381 my $vectors = $net->{queues
} * 2 + 2;
1382 $tmpstr .= ",vectors=$vectors,mq=on";
1384 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1386 if ($use_old_bios_files) {
1388 if ($device eq 'virtio-net-pci') {
1389 $romfile = 'pxe-virtio.rom';
1390 } elsif ($device eq 'e1000') {
1391 $romfile = 'pxe-e1000.rom';
1392 } elsif ($device eq 'ne2k') {
1393 $romfile = 'pxe-ne2k_pci.rom';
1394 } elsif ($device eq 'pcnet') {
1395 $romfile = 'pxe-pcnet.rom';
1396 } elsif ($device eq 'rtl8139') {
1397 $romfile = 'pxe-rtl8139.rom';
1399 $tmpstr .= ",romfile=$romfile" if $romfile;
1405 sub print_netdev_full
{
1406 my ($vmid, $conf, $net, $netid, $hotplug) = @_;
1409 if ($netid =~ m/^net(\d+)$/) {
1413 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1415 my $ifname = "tap${vmid}i$i";
1417 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1418 die "interface name '$ifname' is too long (max 15 character)\n"
1419 if length($ifname) >= 16;
1421 my $vhostparam = '';
1422 $vhostparam = ',vhost=on' if $kernel_has_vhost_net && $net->{model
} eq 'virtio';
1424 my $vmname = $conf->{name
} || "vm$vmid";
1427 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1429 if ($net->{bridge
}) {
1430 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1432 $netdev = "type=user,id=$netid,hostname=$vmname";
1435 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1440 sub drive_is_cdrom
{
1443 return $drive && $drive->{media
} && ($drive->{media
} eq 'cdrom');
1452 foreach my $kvp (split(/,/, $data)) {
1454 if ($kvp =~ m/^memory=(\S+)$/) {
1455 $res->{memory
} = $1;
1456 } elsif ($kvp =~ m/^policy=(preferred|bind|interleave)$/) {
1457 $res->{policy
} = $1;
1458 } elsif ($kvp =~ m/^cpus=(\d+)(-(\d+))?$/) {
1459 $res->{cpus
}->{start
} = $1;
1460 $res->{cpus
}->{end
} = $3;
1461 } elsif ($kvp =~ m/^hostnodes=(\d+)(-(\d+))?$/) {
1462 $res->{hostnodes
}->{start
} = $1;
1463 $res->{hostnodes
}->{end
} = $3;
1475 return undef if !$value;
1478 my @list = split(/,/, $value);
1482 foreach my $kv (@list) {
1484 if ($kv =~ m/^(host=)?([a-f0-9]{2}:[a-f0-9]{2})(\.([a-f0-9]))?$/) {
1487 push @{$res->{pciid
}}, { id
=> $2 , function
=> $4};
1490 my $pcidevices = lspci
($2);
1491 $res->{pciid
} = $pcidevices->{$2};
1493 } elsif ($kv =~ m/^rombar=(on|off)$/) {
1494 $res->{rombar
} = $1;
1495 } elsif ($kv =~ m/^x-vga=(on|off)$/) {
1496 $res->{'x-vga'} = $1;
1497 } elsif ($kv =~ m/^pcie=(\d+)$/) {
1498 $res->{pcie
} = 1 if $1 == 1;
1500 warn "unknown hostpci setting '$kv'\n";
1504 return undef if !$found;
1509 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1515 foreach my $kvp (split(/,/, $data)) {
1517 if ($kvp =~ m/^(ne2k_pci|e1000|e1000-82540em|e1000-82544gc|e1000-82545em|rtl8139|pcnet|virtio|ne2k_isa|i82551|i82557b|i82559er|vmxnet3)(=([0-9a-f]{2}(:[0-9a-f]{2}){5}))?$/i) {
1519 my $mac = defined($3) ?
uc($3) : PVE
::Tools
::random_ether_addr
();
1520 $res->{model
} = $model;
1521 $res->{macaddr
} = $mac;
1522 } elsif ($kvp =~ m/^bridge=(\S+)$/) {
1523 $res->{bridge
} = $1;
1524 } elsif ($kvp =~ m/^queues=(\d+)$/) {
1525 $res->{queues
} = $1;
1526 } elsif ($kvp =~ m/^rate=(\d+(\.\d+)?)$/) {
1528 } elsif ($kvp =~ m/^tag=(\d+)$/) {
1530 } elsif ($kvp =~ m/^trunks=([0-9;]+)$/) {
1531 $res->{trunks
} = $1;
1532 } elsif ($kvp =~ m/^firewall=([01])$/) {
1533 $res->{firewall
} = $1;
1534 } elsif ($kvp =~ m/^link_down=([01])$/) {
1535 $res->{link_down
} = $1;
1542 return undef if !$res->{model
};
1550 my $res = "$net->{model}";
1551 $res .= "=$net->{macaddr}" if $net->{macaddr
};
1552 $res .= ",bridge=$net->{bridge}" if $net->{bridge
};
1553 $res .= ",rate=$net->{rate}" if $net->{rate
};
1554 $res .= ",tag=$net->{tag}" if $net->{tag
};
1555 $res .= ",trunks=$net->{trunks}" if $net->{trunks
};
1556 $res .= ",firewall=1" if $net->{firewall
};
1557 $res .= ",link_down=1" if $net->{link_down
};
1558 $res .= ",queues=$net->{queues}" if $net->{queues
};
1563 sub add_random_macs
{
1564 my ($settings) = @_;
1566 foreach my $opt (keys %$settings) {
1567 next if $opt !~ m/^net(\d+)$/;
1568 my $net = parse_net
($settings->{$opt});
1570 $settings->{$opt} = print_net
($net);
1574 sub vm_is_volid_owner
{
1575 my ($storecfg, $vmid, $volid) = @_;
1577 if ($volid !~ m
|^/|) {
1579 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
1580 if ($owner && ($owner == $vmid)) {
1588 sub split_flagged_list
{
1589 my $text = shift || '';
1590 $text =~ s/[,;]/ /g;
1592 return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
1595 sub join_flagged_list
{
1596 my ($how, $lst) = @_;
1597 join $how, map { $lst->{$_} . $_ } keys %$lst;
1600 sub vmconfig_delete_pending_option
{
1601 my ($conf, $key, $force) = @_;
1603 delete $conf->{pending
}->{$key};
1604 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
1605 $pending_delete_hash->{$key} = $force ?
'!' : '';
1606 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
1609 sub vmconfig_undelete_pending_option
{
1610 my ($conf, $key) = @_;
1612 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
1613 delete $pending_delete_hash->{$key};
1615 if (%$pending_delete_hash) {
1616 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
1618 delete $conf->{pending
}->{delete};
1622 sub vmconfig_register_unused_drive
{
1623 my ($storecfg, $vmid, $conf, $drive) = @_;
1625 if (!drive_is_cdrom
($drive)) {
1626 my $volid = $drive->{file
};
1627 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
1628 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
1633 sub vmconfig_cleanup_pending
{
1636 # remove pending changes when nothing changed
1638 foreach my $opt (keys %{$conf->{pending
}}) {
1639 if (defined($conf->{$opt}) && ($conf->{pending
}->{$opt} eq $conf->{$opt})) {
1641 delete $conf->{pending
}->{$opt};
1645 my $current_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
1646 my $pending_delete_hash = {};
1647 while (my ($opt, $force) = each %$current_delete_hash) {
1648 if (defined($conf->{$opt})) {
1649 $pending_delete_hash->{$opt} = $force;
1655 if (%$pending_delete_hash) {
1656 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
1658 delete $conf->{pending
}->{delete};
1664 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
1665 my $smbios1_desc = {
1668 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
1669 format_description
=> 'UUID',
1675 format_description
=> 'str',
1681 format_description
=> 'str',
1687 format_description
=> 'name',
1693 format_description
=> 'name',
1699 format_description
=> 'str',
1705 format_description
=> 'str',
1713 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_desc, $data) };
1720 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_desc);
1723 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_desc);
1725 PVE
::JSONSchema
::register_format
('pve-qm-bootdisk', \
&verify_bootdisk
);
1726 sub verify_bootdisk
{
1727 my ($value, $noerr) = @_;
1729 return $value if is_valid_drivename
($value);
1731 return undef if $noerr;
1733 die "invalid boot disk '$value'\n";
1736 PVE
::JSONSchema
::register_format
('pve-qm-numanode', \
&verify_numa
);
1738 my ($value, $noerr) = @_;
1740 return $value if parse_numa
($value);
1742 return undef if $noerr;
1744 die "unable to parse numa options\n";
1747 PVE
::JSONSchema
::register_format
('pve-qm-net', \
&verify_net
);
1749 my ($value, $noerr) = @_;
1751 return $value if parse_net
($value);
1753 return undef if $noerr;
1755 die "unable to parse network options\n";
1758 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', \
&verify_hostpci
);
1759 sub verify_hostpci
{
1760 my ($value, $noerr) = @_;
1762 return $value if parse_hostpci
($value);
1764 return undef if $noerr;
1766 die "unable to parse pci id\n";
1769 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', \
&verify_watchdog
);
1770 sub verify_watchdog
{
1771 my ($value, $noerr) = @_;
1773 return $value if parse_watchdog
($value);
1775 return undef if $noerr;
1777 die "unable to parse watchdog options\n";
1780 sub parse_watchdog
{
1783 return undef if !$value;
1787 foreach my $p (split(/,/, $value)) {
1788 next if $p =~ m/^\s*$/;
1790 if ($p =~ m/^(model=)?(i6300esb|ib700)$/) {
1792 } elsif ($p =~ m/^(action=)?(reset|shutdown|poweroff|pause|debug|none)$/) {
1793 $res->{action
} = $2;
1802 sub parse_usb_device
{
1805 return undef if !$value;
1808 if ($value =~ m/^(0x)?([0-9A-Fa-f]{4}):(0x)?([0-9A-Fa-f]{4})$/) {
1809 $res->{vendorid
} = $2;
1810 $res->{productid
} = $4;
1811 } elsif ($value =~ m/^(\d+)\-(\d+(\.\d+)*)$/) {
1812 $res->{hostbus
} = $1;
1813 $res->{hostport
} = $2;
1814 } elsif ($value =~ m/^spice$/i) {
1823 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
1824 sub verify_usb_device
{
1825 my ($value, $noerr) = @_;
1827 return $value if parse_usb_device
($value);
1829 return undef if $noerr;
1831 die "unable to parse usb device\n";
1834 # add JSON properties for create and set function
1835 sub json_config_properties
{
1838 foreach my $opt (keys %$confdesc) {
1839 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate';
1840 $prop->{$opt} = $confdesc->{$opt};
1847 my ($key, $value) = @_;
1849 die "unknown setting '$key'\n" if !$confdesc->{$key};
1851 my $type = $confdesc->{$key}->{type
};
1853 if (!defined($value)) {
1854 die "got undefined value\n";
1857 if ($value =~ m/[\n\r]/) {
1858 die "property contains a line feed\n";
1861 if ($type eq 'boolean') {
1862 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
1863 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
1864 die "type check ('boolean') failed - got '$value'\n";
1865 } elsif ($type eq 'integer') {
1866 return int($1) if $value =~ m/^(\d+)$/;
1867 die "type check ('integer') failed - got '$value'\n";
1868 } elsif ($type eq 'number') {
1869 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
1870 die "type check ('number') failed - got '$value'\n";
1871 } elsif ($type eq 'string') {
1872 if (my $fmt = $confdesc->{$key}->{format
}) {
1873 if ($fmt eq 'pve-qm-drive') {
1874 # special case - we need to pass $key to parse_drive()
1875 my $drive = parse_drive
($key, $value);
1876 return $value if $drive;
1877 die "unable to parse drive options\n";
1879 PVE
::JSONSchema
::check_format
($fmt, $value);
1882 $value =~ s/^\"(.*)\"$/$1/;
1885 die "internal error"
1889 sub check_iommu_support
{
1890 #fixme : need to check IOMMU support
1891 #http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM
1901 my $conf = PVE
::QemuConfig-
>config_file($vmid);
1902 utime undef, undef, $conf;
1906 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
1908 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
1910 my $conf = PVE
::QemuConfig-
>load_config($vmid);
1912 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
1914 # only remove disks owned by this VM
1915 foreach_drive
($conf, sub {
1916 my ($ds, $drive) = @_;
1918 return if drive_is_cdrom
($drive);
1920 my $volid = $drive->{file
};
1922 return if !$volid || $volid =~ m
|^/|;
1924 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
1925 return if !$path || !$owner || ($owner != $vmid);
1927 PVE
::Storage
::vdisk_free
($storecfg, $volid);
1930 if ($keep_empty_config) {
1931 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
1936 # also remove unused disk
1938 my $dl = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
1941 PVE
::Storage
::foreach_volid
($dl, sub {
1942 my ($volid, $sid, $volname, $d) = @_;
1943 PVE
::Storage
::vdisk_free
($storecfg, $volid);
1952 sub parse_vm_config
{
1953 my ($filename, $raw) = @_;
1955 return undef if !defined($raw);
1958 digest
=> Digest
::SHA
::sha1_hex
($raw),
1963 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
1964 || die "got strange filename '$filename'";
1972 my @lines = split(/\n/, $raw);
1973 foreach my $line (@lines) {
1974 next if $line =~ m/^\s*$/;
1976 if ($line =~ m/^\[PENDING\]\s*$/i) {
1977 $section = 'pending';
1978 if (defined($descr)) {
1980 $conf->{description
} = $descr;
1983 $conf = $res->{$section} = {};
1986 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
1988 if (defined($descr)) {
1990 $conf->{description
} = $descr;
1993 $conf = $res->{snapshots
}->{$section} = {};
1997 if ($line =~ m/^\#(.*)\s*$/) {
1998 $descr = '' if !defined($descr);
1999 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2003 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2004 $descr = '' if !defined($descr);
2005 $descr .= PVE
::Tools
::decode_text
($2);
2006 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2007 $conf->{snapstate
} = $1;
2008 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2011 $conf->{$key} = $value;
2012 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2014 if ($section eq 'pending') {
2015 $conf->{delete} = $value; # we parse this later
2017 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2019 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(\S+)\s*$/) {
2022 eval { $value = check_type
($key, $value); };
2024 warn "vm $vmid - unable to parse value of '$key' - $@";
2026 my $fmt = $confdesc->{$key}->{format
};
2027 if ($fmt && $fmt eq 'pve-qm-drive') {
2028 my $v = parse_drive
($key, $value);
2029 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2030 $v->{file
} = $volid;
2031 $value = print_drive
($vmid, $v);
2033 warn "vm $vmid - unable to parse value of '$key'\n";
2038 if ($key eq 'cdrom') {
2039 $conf->{ide2
} = $value;
2041 $conf->{$key} = $value;
2047 if (defined($descr)) {
2049 $conf->{description
} = $descr;
2051 delete $res->{snapstate
}; # just to be sure
2056 sub write_vm_config
{
2057 my ($filename, $conf) = @_;
2059 delete $conf->{snapstate
}; # just to be sure
2061 if ($conf->{cdrom
}) {
2062 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2063 $conf->{ide2
} = $conf->{cdrom
};
2064 delete $conf->{cdrom
};
2067 # we do not use 'smp' any longer
2068 if ($conf->{sockets
}) {
2069 delete $conf->{smp
};
2070 } elsif ($conf->{smp
}) {
2071 $conf->{sockets
} = $conf->{smp
};
2072 delete $conf->{cores
};
2073 delete $conf->{smp
};
2076 my $used_volids = {};
2078 my $cleanup_config = sub {
2079 my ($cref, $pending, $snapname) = @_;
2081 foreach my $key (keys %$cref) {
2082 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2083 $key eq 'snapstate' || $key eq 'pending';
2084 my $value = $cref->{$key};
2085 if ($key eq 'delete') {
2086 die "propertry 'delete' is only allowed in [PENDING]\n"
2088 # fixme: check syntax?
2091 eval { $value = check_type
($key, $value); };
2092 die "unable to parse value of '$key' - $@" if $@;
2094 $cref->{$key} = $value;
2096 if (!$snapname && is_valid_drivename
($key)) {
2097 my $drive = parse_drive
($key, $value);
2098 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2103 &$cleanup_config($conf);
2105 &$cleanup_config($conf->{pending
}, 1);
2107 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2108 die "internal error" if $snapname eq 'pending';
2109 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2112 # remove 'unusedX' settings if we re-add a volume
2113 foreach my $key (keys %$conf) {
2114 my $value = $conf->{$key};
2115 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2116 delete $conf->{$key};
2120 my $generate_raw_config = sub {
2121 my ($conf, $pending) = @_;
2125 # add description as comment to top of file
2126 if (defined(my $descr = $conf->{description
})) {
2128 foreach my $cl (split(/\n/, $descr)) {
2129 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2132 $raw .= "#\n" if $pending;
2136 foreach my $key (sort keys %$conf) {
2137 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2138 $raw .= "$key: $conf->{$key}\n";
2143 my $raw = &$generate_raw_config($conf);
2145 if (scalar(keys %{$conf->{pending
}})){
2146 $raw .= "\n[PENDING]\n";
2147 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2150 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2151 $raw .= "\n[$snapname]\n";
2152 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2162 # we use static defaults from our JSON schema configuration
2163 foreach my $key (keys %$confdesc) {
2164 if (defined(my $default = $confdesc->{$key}->{default})) {
2165 $res->{$key} = $default;
2169 my $conf = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
2170 $res->{keyboard
} = $conf->{keyboard
} if $conf->{keyboard
};
2176 my $vmlist = PVE
::Cluster
::get_vmlist
();
2178 return $res if !$vmlist || !$vmlist->{ids
};
2179 my $ids = $vmlist->{ids
};
2181 foreach my $vmid (keys %$ids) {
2182 my $d = $ids->{$vmid};
2183 next if !$d->{node
} || $d->{node
} ne $nodename;
2184 next if !$d->{type
} || $d->{type
} ne 'qemu';
2185 $res->{$vmid}->{exists} = 1;
2190 # test if VM uses local resources (to prevent migration)
2191 sub check_local_resources
{
2192 my ($conf, $noerr) = @_;
2196 $loc_res = 1 if $conf->{hostusb
}; # old syntax
2197 $loc_res = 1 if $conf->{hostpci
}; # old syntax
2199 foreach my $k (keys %$conf) {
2200 next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2201 # sockets are safe: they will recreated be on the target side post-migrate
2202 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2203 $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2206 die "VM uses local resources\n" if $loc_res && !$noerr;
2211 # check if used storages are available on all nodes (use by migrate)
2212 sub check_storage_availability
{
2213 my ($storecfg, $conf, $node) = @_;
2215 foreach_drive
($conf, sub {
2216 my ($ds, $drive) = @_;
2218 my $volid = $drive->{file
};
2221 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2224 # check if storage is available on both nodes
2225 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2226 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2230 # list nodes where all VM images are available (used by has_feature API)
2232 my ($conf, $storecfg) = @_;
2234 my $nodelist = PVE
::Cluster
::get_nodelist
();
2235 my $nodehash = { map { $_ => 1 } @$nodelist };
2236 my $nodename = PVE
::INotify
::nodename
();
2238 foreach_drive
($conf, sub {
2239 my ($ds, $drive) = @_;
2241 my $volid = $drive->{file
};
2244 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2246 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2247 if ($scfg->{disable
}) {
2249 } elsif (my $avail = $scfg->{nodes
}) {
2250 foreach my $node (keys %$nodehash) {
2251 delete $nodehash->{$node} if !$avail->{$node};
2253 } elsif (!$scfg->{shared
}) {
2254 foreach my $node (keys %$nodehash) {
2255 delete $nodehash->{$node} if $node ne $nodename
2265 my ($pidfile, $pid) = @_;
2267 my $fh = IO
::File-
>new("/proc/$pid/cmdline", "r");
2271 return undef if !$line;
2272 my @param = split(/\0/, $line);
2274 my $cmd = $param[0];
2275 return if !$cmd || ($cmd !~ m
|kvm
$| && $cmd !~ m
|qemu-system-x86_64
$|);
2277 for (my $i = 0; $i < scalar (@param); $i++) {
2280 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2281 my $p = $param[$i+1];
2282 return 1 if $p && ($p eq $pidfile);
2291 my ($vmid, $nocheck, $node) = @_;
2293 my $filename = PVE
::QemuConfig-
>config_file($vmid, $node);
2295 die "unable to find configuration file for VM $vmid - no such machine\n"
2296 if !$nocheck && ! -f
$filename;
2298 my $pidfile = pidfile_name
($vmid);
2300 if (my $fd = IO
::File-
>new("<$pidfile")) {
2305 my $mtime = $st->mtime;
2306 if ($mtime > time()) {
2307 warn "file '$filename' modified in future\n";
2310 if ($line =~ m/^(\d+)$/) {
2312 if (check_cmdline
($pidfile, $pid)) {
2313 if (my $pinfo = PVE
::ProcFSTools
::check_process_running
($pid)) {
2325 my $vzlist = config_list
();
2327 my $fd = IO
::Dir-
>new($var_run_tmpdir) || return $vzlist;
2329 while (defined(my $de = $fd->read)) {
2330 next if $de !~ m/^(\d+)\.pid$/;
2332 next if !defined($vzlist->{$vmid});
2333 if (my $pid = check_running
($vmid)) {
2334 $vzlist->{$vmid}->{pid
} = $pid;
2342 my ($storecfg, $conf) = @_;
2344 my $bootdisk = $conf->{bootdisk
};
2345 return undef if !$bootdisk;
2346 return undef if !is_valid_drivename
($bootdisk);
2348 return undef if !$conf->{$bootdisk};
2350 my $drive = parse_drive
($bootdisk, $conf->{$bootdisk});
2351 return undef if !defined($drive);
2353 return undef if drive_is_cdrom
($drive);
2355 my $volid = $drive->{file
};
2356 return undef if !$volid;
2358 return $drive->{size
};
2361 my $last_proc_pid_stat;
2363 # get VM status information
2364 # This must be fast and should not block ($full == false)
2365 # We only query KVM using QMP if $full == true (this can be slow)
2367 my ($opt_vmid, $full) = @_;
2371 my $storecfg = PVE
::Storage
::config
();
2373 my $list = vzlist
();
2374 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2376 my $cpucount = $cpuinfo->{cpus
} || 1;
2378 foreach my $vmid (keys %$list) {
2379 next if $opt_vmid && ($vmid ne $opt_vmid);
2381 my $cfspath = PVE
::QemuConfig-
>cfs_config_path($vmid);
2382 my $conf = PVE
::Cluster
::cfs_read_file
($cfspath) || {};
2385 $d->{pid
} = $list->{$vmid}->{pid
};
2387 # fixme: better status?
2388 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
2390 my $size = disksize
($storecfg, $conf);
2391 if (defined($size)) {
2392 $d->{disk
} = 0; # no info available
2393 $d->{maxdisk
} = $size;
2399 $d->{cpus
} = ($conf->{sockets
} || 1) * ($conf->{cores
} || 1);
2400 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
2401 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
2403 $d->{name
} = $conf->{name
} || "VM $vmid";
2404 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024) : 0;
2406 if ($conf->{balloon
}) {
2407 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
2408 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
} : 1000;
2419 $d->{diskwrite
} = 0;
2421 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
2426 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
2427 foreach my $dev (keys %$netdev) {
2428 next if $dev !~ m/^tap([1-9]\d*)i/;
2430 my $d = $res->{$vmid};
2433 $d->{netout
} += $netdev->{$dev}->{receive
};
2434 $d->{netin
} += $netdev->{$dev}->{transmit
};
2437 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
2438 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
2443 my $ctime = gettimeofday
;
2445 foreach my $vmid (keys %$list) {
2447 my $d = $res->{$vmid};
2448 my $pid = $d->{pid
};
2451 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
2452 next if !$pstat; # not running
2454 my $used = $pstat->{utime} + $pstat->{stime
};
2456 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
2458 if ($pstat->{vsize
}) {
2459 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
2462 my $old = $last_proc_pid_stat->{$pid};
2464 $last_proc_pid_stat->{$pid} = {
2472 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
2474 if ($dtime > 1000) {
2475 my $dutime = $used - $old->{used
};
2477 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
2478 $last_proc_pid_stat->{$pid} = {
2484 $d->{cpu
} = $old->{cpu
};
2488 return $res if !$full;
2490 my $qmpclient = PVE
::QMPClient-
>new();
2492 my $ballooncb = sub {
2493 my ($vmid, $resp) = @_;
2495 my $info = $resp->{'return'};
2496 return if !$info->{max_mem
};
2498 my $d = $res->{$vmid};
2500 # use memory assigned to VM
2501 $d->{maxmem
} = $info->{max_mem
};
2502 $d->{balloon
} = $info->{actual
};
2504 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
2505 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
2506 $d->{freemem
} = $info->{free_mem
};
2509 $d->{ballooninfo
} = $info;
2512 my $blockstatscb = sub {
2513 my ($vmid, $resp) = @_;
2514 my $data = $resp->{'return'} || [];
2515 my $totalrdbytes = 0;
2516 my $totalwrbytes = 0;
2518 for my $blockstat (@$data) {
2519 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
2520 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
2522 $blockstat->{device
} =~ s/drive-//;
2523 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
2525 $res->{$vmid}->{diskread
} = $totalrdbytes;
2526 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
2529 my $statuscb = sub {
2530 my ($vmid, $resp) = @_;
2532 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
2533 # this fails if ballon driver is not loaded, so this must be
2534 # the last commnand (following command are aborted if this fails).
2535 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
2537 my $status = 'unknown';
2538 if (!defined($status = $resp->{'return'}->{status
})) {
2539 warn "unable to get VM status\n";
2543 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
2546 foreach my $vmid (keys %$list) {
2547 next if $opt_vmid && ($vmid ne $opt_vmid);
2548 next if !$res->{$vmid}->{pid
}; # not running
2549 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
2552 $qmpclient->queue_execute(undef, 1);
2554 foreach my $vmid (keys %$list) {
2555 next if $opt_vmid && ($vmid ne $opt_vmid);
2556 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
2563 my ($conf, $vmid, $memory, $sockets, $func) = @_;
2566 my $current_size = 1024;
2567 my $dimm_size = 512;
2568 return if $current_size == $memory;
2570 for (my $j = 0; $j < 8; $j++) {
2571 for (my $i = 0; $i < 32; $i++) {
2572 my $name = "dimm${dimm_id}";
2574 my $numanode = $i % $sockets;
2575 $current_size += $dimm_size;
2576 &$func($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory);
2577 return $current_size if $current_size >= $memory;
2583 sub foreach_reverse_dimm
{
2584 my ($conf, $vmid, $memory, $sockets, $func) = @_;
2587 my $current_size = 4177920;
2588 my $dimm_size = 65536;
2589 return if $current_size == $memory;
2591 for (my $j = 0; $j < 8; $j++) {
2592 for (my $i = 0; $i < 32; $i++) {
2593 my $name = "dimm${dimm_id}";
2595 my $numanode = $i % $sockets;
2596 $current_size -= $dimm_size;
2597 &$func($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory);
2598 return $current_size if $current_size <= $memory;
2605 my ($conf, $func) = @_;
2607 foreach my $ds (valid_drive_names
()) {
2608 next if !defined($conf->{$ds});
2610 my $drive = parse_drive
($ds, $conf->{$ds});
2613 &$func($ds, $drive);
2618 my ($conf, $func) = @_;
2622 my $test_volid = sub {
2623 my ($volid, $is_cdrom) = @_;
2627 $volhash->{$volid} = $is_cdrom || 0;
2630 foreach_drive
($conf, sub {
2631 my ($ds, $drive) = @_;
2632 &$test_volid($drive->{file
}, drive_is_cdrom
($drive));
2635 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2636 my $snap = $conf->{snapshots
}->{$snapname};
2637 &$test_volid($snap->{vmstate
}, 0);
2638 foreach_drive
($snap, sub {
2639 my ($ds, $drive) = @_;
2640 &$test_volid($drive->{file
}, drive_is_cdrom
($drive));
2644 foreach my $volid (keys %$volhash) {
2645 &$func($volid, $volhash->{$volid});
2649 sub vga_conf_has_spice
{
2652 return 0 if !$vga || $vga !~ m/^qxl([234])?$/;
2657 sub config_to_command
{
2658 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
2661 my $globalFlags = [];
2662 my $machineFlags = [];
2668 my $kvmver = kvm_user_version
();
2669 my $vernum = 0; # unknown
2670 my $ostype = $conf->{ostype
};
2671 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
2672 $vernum = $1*1000000+$2*1000;
2673 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
2674 $vernum = $1*1000000+$2*1000+$3;
2677 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
2679 my $have_ovz = -f
'/proc/vz/vestat';
2681 my $q35 = machine_type_is_q35
($conf);
2682 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
2683 my $machine_type = $forcemachine || $conf->{machine
};
2684 my $use_old_bios_files = undef;
2685 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
2687 my $cpuunits = defined($conf->{cpuunits
}) ?
2688 $conf->{cpuunits
} : $defaults->{cpuunits
};
2690 push @$cmd, '/usr/bin/systemd-run';
2691 push @$cmd, '--scope';
2692 push @$cmd, '--slice', "qemu";
2693 push @$cmd, '--unit', $vmid;
2694 # set KillMode=none, so that systemd don't kill those scopes
2695 # at shutdown (pve-manager service should stop the VMs instead)
2696 push @$cmd, '-p', "KillMode=none";
2697 push @$cmd, '-p', "CPUShares=$cpuunits";
2698 if ($conf->{cpulimit
}) {
2699 my $cpulimit = int($conf->{cpulimit
} * 100);
2700 push @$cmd, '-p', "CPUQuota=$cpulimit\%";
2703 push @$cmd, '/usr/bin/kvm';
2705 push @$cmd, '-id', $vmid;
2709 my $qmpsocket = qmp_socket
($vmid);
2710 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
2711 push @$cmd, '-mon', "chardev=qmp,mode=control";
2714 push @$cmd, '-pidfile' , pidfile_name
($vmid);
2716 push @$cmd, '-daemonize';
2718 if ($conf->{smbios1
}) {
2719 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
2722 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
2723 my $ovmfvar = "OVMF_VARS-pure-efi.fd";
2724 my $ovmfvar_src = "/usr/share/kvm/$ovmfvar";
2725 my $ovmfvar_dst = "/tmp/$vmid-$ovmfvar";
2726 PVE
::Tools
::file_copy
($ovmfvar_src, $ovmfvar_dst, 256*1024);
2727 push @$cmd, '-drive', "if=pflash,format=raw,readonly,file=/usr/share/kvm/OVMF-pure-efi.fd";
2728 push @$cmd, '-drive', "if=pflash,format=raw,file=$ovmfvar_dst";
2732 # the q35 chipset support native usb2, so we enable usb controller
2733 # by default for this machine type
2734 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35.cfg';
2736 $pciaddr = print_pci_addr
("piix3", $bridges);
2737 push @$devices, '-device', "piix3-usb-uhci,id=uhci$pciaddr.0x2";
2740 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
2741 next if !$conf->{"usb$i"};
2742 my $d = eval { PVE
::JSONSchema
::parse_property_string
($usbdesc->{format
},$conf->{"usb$i"}) };
2743 next if !$d || $d->{usb3
}; # do not add usb2 controller if we have only usb3 devices
2746 # include usb device config
2747 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-usb.cfg' if $use_usb2;
2750 # add usb3 controller if needed
2753 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
2754 next if !$conf->{"usb$i"};
2755 my $d = eval { PVE
::JSONSchema
::parse_property_string
($usbdesc->{format
},$conf->{"usb$i"}) };
2756 next if !$d || !$d->{usb3
};
2760 $pciaddr = print_pci_addr
("xhci", $bridges);
2761 push @$devices, '-device', "nec-usb-xhci,id=xhci$pciaddr" if $use_usb3;
2763 my $vga = $conf->{vga
};
2765 my $qxlnum = vga_conf_has_spice
($vga);
2766 $vga = 'qxl' if $qxlnum;
2769 if ($conf->{ostype
} && ($conf->{ostype
} eq 'win8' ||
2770 $conf->{ostype
} eq 'win7' ||
2771 $conf->{ostype
} eq 'w2k8')) {
2778 # enable absolute mouse coordinates (needed by vnc)
2780 if (defined($conf->{tablet
})) {
2781 $tablet = $conf->{tablet
};
2783 $tablet = $defaults->{tablet
};
2784 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
2785 $tablet = 0 if $vga =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
2788 push @$devices, '-device', print_tabletdevice_full
($conf) if $tablet;
2792 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
2793 my $d = parse_hostpci
($conf->{"hostpci$i"});
2796 my $pcie = $d->{pcie
};
2798 die "q35 machine model is not enabled" if !$q35;
2799 $pciaddr = print_pcie_addr
("hostpci$i");
2801 $pciaddr = print_pci_addr
("hostpci$i", $bridges);
2804 my $rombar = $d->{rombar
} && $d->{rombar
} eq 'off' ?
",rombar=0" : "";
2805 my $xvga = $d->{'x-vga'} && $d->{'x-vga'} eq 'on' ?
",x-vga=on" : "";
2806 if ($xvga && $xvga ne '') {
2809 if ($ostype eq 'win7' || $ostype eq 'win8' || $ostype eq 'w2k8') {
2810 push @$cpuFlags , 'hv_vendor_id=proxmox';
2812 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
2816 my $pcidevices = $d->{pciid
};
2817 my $multifunction = 1 if @$pcidevices > 1;
2820 foreach my $pcidevice (@$pcidevices) {
2822 my $id = "hostpci$i";
2823 $id .= ".$j" if $multifunction;
2824 my $addr = $pciaddr;
2825 $addr .= ".$j" if $multifunction;
2826 my $devicestr = "vfio-pci,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
2829 $devicestr .= "$rombar$xvga";
2830 $devicestr .= ",multifunction=on" if $multifunction;
2833 push @$devices, '-device', $devicestr;
2839 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
2840 next if !$conf->{"usb$i"};
2841 my $d = eval { PVE
::JSONSchema
::parse_property_string
($usbdesc->{format
},$conf->{"usb$i"}) };
2844 # if it is a usb3 device, attach it to the xhci controller, else omit the bus option
2846 if (defined($d->{usb3
}) && $d->{usb3
}) {
2847 $usbbus = ',bus=xhci.0';
2850 if (defined($d->{host
})) {
2851 $d = parse_usb_device
($d->{host
});
2852 if (defined($d->{vendorid
}) && defined($d->{productid
})) {
2853 push @$devices, '-device', "usb-host$usbbus,vendorid=0x$d->{vendorid},productid=0x$d->{productid}";
2854 } elsif (defined($d->{hostbus
}) && defined($d->{hostport
})) {
2855 push @$devices, '-device', "usb-host$usbbus,hostbus=$d->{hostbus},hostport=$d->{hostport}";
2856 } elsif (defined($d->{spice
}) && $d->{spice
}) {
2857 # usb redir support for spice, currently no usb3
2858 push @$devices, '-chardev', "spicevmc,id=usbredirchardev$i,name=usbredir";
2859 push @$devices, '-device', "usb-redir,chardev=usbredirchardev$i,id=usbredirdev$i,bus=ehci.0";
2865 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
2866 if (my $path = $conf->{"serial$i"}) {
2867 if ($path eq 'socket') {
2868 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
2869 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
2870 push @$devices, '-device', "isa-serial,chardev=serial$i";
2872 die "no such serial device\n" if ! -c
$path;
2873 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
2874 push @$devices, '-device', "isa-serial,chardev=serial$i";
2880 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
2881 if (my $path = $conf->{"parallel$i"}) {
2882 die "no such parallel device\n" if ! -c
$path;
2883 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
2884 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
2885 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
2889 my $vmname = $conf->{name
} || "vm$vmid";
2891 push @$cmd, '-name', $vmname;
2894 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
2895 $sockets = $conf->{sockets
} if $conf->{sockets
};
2897 my $cores = $conf->{cores
} || 1;
2899 my $maxcpus = $sockets * $cores;
2901 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
2903 my $allowed_vcpus = $cpuinfo->{cpus
};
2905 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
2906 if ($allowed_vcpus < $maxcpus);
2908 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
2910 push @$cmd, '-nodefaults';
2912 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
2914 my $bootindex_hash = {};
2916 foreach my $o (split(//, $bootorder)) {
2917 $bootindex_hash->{$o} = $i*100;
2921 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000";
2923 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
2925 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
2927 push @$cmd, '-vga', $vga if $vga && $vga !~ m/^serial\d+$/; # for kvm 77 and later
2929 if ($vga && $vga !~ m/^serial\d+$/ && $vga ne 'none'){
2930 my $socket = vnc_socket
($vmid);
2931 push @$cmd, '-vnc', "unix:$socket,x509,password";
2933 push @$cmd, '-nographic';
2937 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
2939 my $nokvm = defined($conf->{kvm
}) && $conf->{kvm
} == 0 ?
1 : 0;
2940 my $useLocaltime = $conf->{localtime};
2943 # other, wxp, w2k, w2k3, w2k8, wvista, win7, win8, l24, l26, solaris
2945 if ($ostype =~ m/^w/) { # windows
2946 $useLocaltime = 1 if !defined($conf->{localtime});
2948 # use time drift fix when acpi is enabled
2949 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
2950 $tdf = 1 if !defined($conf->{tdf
});
2954 if ($ostype eq 'win7' || $ostype eq 'win8' || $ostype eq 'w2k8' ||
2955 $ostype eq 'wvista') {
2956 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
2957 push @$cmd, '-no-hpet';
2958 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
2959 push @$cpuFlags , 'hv_spinlocks=0x1fff' if !$nokvm;
2960 push @$cpuFlags , 'hv_vapic' if !$nokvm;
2961 push @$cpuFlags , 'hv_time' if !$nokvm;
2964 push @$cpuFlags , 'hv_spinlocks=0xffff' if !$nokvm;
2968 if ($ostype eq 'win7' || $ostype eq 'win8') {
2969 push @$cpuFlags , 'hv_relaxed' if !$nokvm;
2973 push @$rtcFlags, 'driftfix=slew' if $tdf;
2976 push @$machineFlags, 'accel=tcg';
2978 die "No accelerator found!\n" if !$cpuinfo->{hvm
};
2981 if ($machine_type) {
2982 push @$machineFlags, "type=${machine_type}";
2985 if ($conf->{startdate
}) {
2986 push @$rtcFlags, "base=$conf->{startdate}";
2987 } elsif ($useLocaltime) {
2988 push @$rtcFlags, 'base=localtime';
2991 my $cpu = $nokvm ?
"qemu64" : "kvm64";
2992 if (my $cputype = $conf->{cpu
}) {
2993 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpudesc, $cputype)
2994 or die "Cannot parse cpu description: $cputype\n";
2995 $cpu = $cpuconf->{cputype
};
2996 $kvm_off = 1 if $cpuconf->{hidden
};
2999 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64';
3001 push @$cpuFlags , '-x2apic'
3002 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3004 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3006 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3008 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3010 push @$cpuFlags , '+kvm_pv_unhalt' if !$nokvm;
3011 push @$cpuFlags , '+kvm_pv_eoi' if !$nokvm;
3014 push @$cpuFlags, 'enforce' if $cpu ne 'host' && !$nokvm;
3016 push @$cpuFlags, 'kvm=off' if $kvm_off;
3018 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3020 push @$cmd, '-cpu', $cpu;
3022 my $memory = $conf->{memory
} || $defaults->{memory
};
3023 my $static_memory = 0;
3024 my $dimm_memory = 0;
3026 if ($hotplug_features->{memory
}) {
3027 die "Numa need to be enabled for memory hotplug\n" if !$conf->{numa
};
3028 die "Total memory is bigger than ${MAX_MEM}MB\n" if $memory > $MAX_MEM;
3029 $static_memory = $STATICMEM;
3030 die "minimum memory must be ${static_memory}MB\n" if($memory < $static_memory);
3031 $dimm_memory = $memory - $static_memory;
3032 push @$cmd, '-m', "size=${static_memory},slots=255,maxmem=${MAX_MEM}M";
3036 $static_memory = $memory;
3037 push @$cmd, '-m', $static_memory;
3040 if ($conf->{numa
}) {
3042 my $numa_totalmemory = undef;
3043 for (my $i = 0; $i < $MAX_NUMA; $i++) {
3044 next if !$conf->{"numa$i"};
3045 my $numa = parse_numa
($conf->{"numa$i"});
3048 die "missing numa node$i memory value\n" if !$numa->{memory
};
3049 my $numa_memory = $numa->{memory
};
3050 $numa_totalmemory += $numa_memory;
3051 my $numa_object = "memory-backend-ram,id=ram-node$i,size=${numa_memory}M";
3054 my $cpus_start = $numa->{cpus
}->{start
};
3055 die "missing numa node$i cpus\n" if !defined($cpus_start);
3056 my $cpus_end = $numa->{cpus
}->{end
} if defined($numa->{cpus
}->{end
});
3057 my $cpus = $cpus_start;
3058 if (defined($cpus_end)) {
3059 $cpus .= "-$cpus_end";
3060 die "numa node$i : cpu range $cpus is incorrect\n" if $cpus_end <= $cpus_start;
3064 my $hostnodes_start = $numa->{hostnodes
}->{start
};
3065 if (defined($hostnodes_start)) {
3066 my $hostnodes_end = $numa->{hostnodes
}->{end
} if defined($numa->{hostnodes
}->{end
});
3067 my $hostnodes = $hostnodes_start;
3068 if (defined($hostnodes_end)) {
3069 $hostnodes .= "-$hostnodes_end";
3070 die "host node $hostnodes range is incorrect\n" if $hostnodes_end <= $hostnodes_start;
3073 my $hostnodes_end_range = defined($hostnodes_end) ?
$hostnodes_end : $hostnodes_start;
3074 for (my $i = $hostnodes_start; $i <= $hostnodes_end_range; $i++ ) {
3075 die "host numa node$i don't exist\n" if ! -d
"/sys/devices/system/node/node$i/";
3079 my $policy = $numa->{policy
};
3080 die "you need to define a policy for hostnode $hostnodes\n" if !$policy;
3081 $numa_object .= ",host-nodes=$hostnodes,policy=$policy";
3084 push @$cmd, '-object', $numa_object;
3085 push @$cmd, '-numa', "node,nodeid=$i,cpus=$cpus,memdev=ram-node$i";
3088 die "total memory for NUMA nodes must be equal to vm static memory\n"
3089 if $numa_totalmemory && $numa_totalmemory != $static_memory;
3091 #if no custom tology, we split memory and cores across numa nodes
3092 if(!$numa_totalmemory) {
3094 my $numa_memory = ($static_memory / $sockets) . "M";
3096 for (my $i = 0; $i < $sockets; $i++) {
3098 my $cpustart = ($cores * $i);
3099 my $cpuend = ($cpustart + $cores - 1) if $cores && $cores > 1;
3100 my $cpus = $cpustart;
3101 $cpus .= "-$cpuend" if $cpuend;
3103 push @$cmd, '-object', "memory-backend-ram,size=$numa_memory,id=ram-node$i";
3104 push @$cmd, '-numa', "node,nodeid=$i,cpus=$cpus,memdev=ram-node$i";
3109 if ($hotplug_features->{memory
}) {
3110 foreach_dimm
($conf, $vmid, $memory, $sockets, sub {
3111 my ($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory) = @_;
3112 push @$cmd, "-object" , "memory-backend-ram,id=mem-$name,size=${dimm_size}M";
3113 push @$cmd, "-device", "pc-dimm,id=$name,memdev=mem-$name,node=$numanode";
3115 #if dimm_memory is not aligned to dimm map
3116 if($current_size > $memory) {
3117 $conf->{memory
} = $current_size;
3118 PVE
::QemuConfig-
>write_config($vmid, $conf);
3123 push @$cmd, '-S' if $conf->{freeze
};
3125 # set keyboard layout
3126 my $kb = $conf->{keyboard
} || $defaults->{keyboard
};
3127 push @$cmd, '-k', $kb if $kb;
3130 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3131 #push @$cmd, '-soundhw', 'es1370';
3132 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3134 if($conf->{agent
}) {
3135 my $qgasocket = qmp_socket
($vmid, 1);
3136 my $pciaddr = print_pci_addr
("qga0", $bridges);
3137 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3138 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3139 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3146 if ($conf->{ostype
} && $conf->{ostype
} =~ m/^w/){
3147 for(my $i = 1; $i < $qxlnum; $i++){
3148 my $pciaddr = print_pci_addr
("vga$i", $bridges);
3149 push @$cmd, '-device', "qxl,id=vga$i,ram_size=67108864,vram_size=33554432$pciaddr";
3152 # assume other OS works like Linux
3153 push @$cmd, '-global', 'qxl-vga.ram_size=134217728';
3154 push @$cmd, '-global', 'qxl-vga.vram_size=67108864';
3158 my $pciaddr = print_pci_addr
("spice", $bridges);
3160 my $nodename = PVE
::INotify
::nodename
();
3161 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3162 $spice_port = PVE
::Tools
::next_spice_port
($pfamily);
3164 push @$devices, '-spice', "tls-port=${spice_port},addr=localhost,tls-ciphers=DES-CBC3-SHA,seamless-migration=on";
3166 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3167 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3168 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3171 # enable balloon by default, unless explicitly disabled
3172 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3173 $pciaddr = print_pci_addr
("balloon0", $bridges);
3174 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3177 if ($conf->{watchdog
}) {
3178 my $wdopts = parse_watchdog
($conf->{watchdog
});
3179 $pciaddr = print_pci_addr
("watchdog", $bridges);
3180 my $watchdog = $wdopts->{model
} || 'i6300esb';
3181 push @$devices, '-device', "$watchdog$pciaddr";
3182 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3186 my $scsicontroller = {};
3187 my $ahcicontroller = {};
3188 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3190 # Add iscsi initiator name if available
3191 if (my $initiator = get_initiator_name
()) {
3192 push @$devices, '-iscsi', "initiator-name=$initiator";
3195 foreach_drive
($conf, sub {
3196 my ($ds, $drive) = @_;
3198 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3199 push @$vollist, $drive->{file
};
3202 $use_virtio = 1 if $ds =~ m/^virtio/;
3204 if (drive_is_cdrom
($drive)) {
3205 if ($bootindex_hash->{d
}) {
3206 $drive->{bootindex
} = $bootindex_hash->{d
};
3207 $bootindex_hash->{d
} += 1;
3210 if ($bootindex_hash->{c
}) {
3211 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3212 $bootindex_hash->{c
} += 1;
3216 if($drive->{interface
} eq 'virtio'){
3217 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3220 if ($drive->{interface
} eq 'scsi') {
3222 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3224 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges);
3225 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3228 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3229 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3230 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3234 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3235 $queues = ",num_queues=$drive->{queues}";
3238 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3239 $scsicontroller->{$controller}=1;
3242 if ($drive->{interface
} eq 'sata') {
3243 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3244 $pciaddr = print_pci_addr
("ahci$controller", $bridges);
3245 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3246 $ahcicontroller->{$controller}=1;
3249 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3250 push @$devices, '-drive',$drive_cmd;
3251 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges);
3254 for (my $i = 0; $i < $MAX_NETS; $i++) {
3255 next if !$conf->{"net$i"};
3256 my $d = parse_net
($conf->{"net$i"});
3259 $use_virtio = 1 if $d->{model
} eq 'virtio';
3261 if ($bootindex_hash->{n
}) {
3262 $d->{bootindex
} = $bootindex_hash->{n
};
3263 $bootindex_hash->{n
} += 1;
3266 my $netdevfull = print_netdev_full
($vmid,$conf,$d,"net$i");
3267 push @$devices, '-netdev', $netdevfull;
3269 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files);
3270 push @$devices, '-device', $netdevicefull;
3275 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3280 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3282 while (my ($k, $v) = each %$bridges) {
3283 $pciaddr = print_pci_addr
("pci.$k");
3284 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3289 if ($conf->{args
}) {
3290 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3294 push @$cmd, @$devices;
3295 push @$cmd, '-rtc', join(',', @$rtcFlags)
3296 if scalar(@$rtcFlags);
3297 push @$cmd, '-machine', join(',', @$machineFlags)
3298 if scalar(@$machineFlags);
3299 push @$cmd, '-global', join(',', @$globalFlags)
3300 if scalar(@$globalFlags);
3302 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3307 return "${var_run_tmpdir}/$vmid.vnc";
3313 my $res = vm_mon_cmd
($vmid, 'query-spice');
3315 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3319 my ($vmid, $qga) = @_;
3320 my $sockettype = $qga ?
'qga' : 'qmp';
3321 return "${var_run_tmpdir}/$vmid.$sockettype";
3326 return "${var_run_tmpdir}/$vmid.pid";
3329 sub vm_devices_list
{
3332 my $res = vm_mon_cmd
($vmid, 'query-pci');
3334 foreach my $pcibus (@$res) {
3335 foreach my $device (@{$pcibus->{devices
}}) {
3336 next if !$device->{'qdev_id'};
3337 if ($device->{'pci_bridge'}) {
3338 $devices->{$device->{'qdev_id'}} = 1;
3339 foreach my $bridge_device (@{$device->{'pci_bridge'}->{devices
}}) {
3340 next if !$bridge_device->{'qdev_id'};
3341 $devices->{$bridge_device->{'qdev_id'}} = 1;
3342 $devices->{$device->{'qdev_id'}}++;
3345 $devices->{$device->{'qdev_id'}} = 1;
3350 my $resblock = vm_mon_cmd
($vmid, 'query-block');
3351 foreach my $block (@$resblock) {
3352 if($block->{device
} =~ m/^drive-(\S+)/){
3357 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
3358 foreach my $mice (@$resmice) {
3359 if ($mice->{name
} eq 'QEMU HID Tablet') {
3360 $devices->{tablet
} = 1;
3369 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
3371 my $q35 = machine_type_is_q35
($conf);
3373 my $devices_list = vm_devices_list
($vmid);
3374 return 1 if defined($devices_list->{$deviceid});
3376 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid); # add PCI bridge if we need it for the device
3378 if ($deviceid eq 'tablet') {
3380 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf));
3382 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3384 qemu_iothread_add
($vmid, $deviceid, $device);
3386 qemu_driveadd
($storecfg, $vmid, $device);
3387 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3389 qemu_deviceadd
($vmid, $devicefull);
3390 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3392 eval { qemu_drivedel
($vmid, $deviceid); };
3397 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3400 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
3401 my $pciaddr = print_pci_addr
($deviceid);
3402 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
3404 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
3406 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
3407 qemu_iothread_add
($vmid, $deviceid, $device);
3408 $devicefull .= ",iothread=iothread-$deviceid";
3411 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
3412 $devicefull .= ",num_queues=$device->{queues}";
3415 qemu_deviceadd
($vmid, $devicefull);
3416 qemu_deviceaddverify
($vmid, $deviceid);
3418 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3420 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device);
3421 qemu_driveadd
($storecfg, $vmid, $device);
3423 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3424 eval { qemu_deviceadd
($vmid, $devicefull); };
3426 eval { qemu_drivedel
($vmid, $deviceid); };
3431 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3433 return undef if !qemu_netdevadd
($vmid, $conf, $device, $deviceid);
3435 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
3436 my $use_old_bios_files = undef;
3437 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3439 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files);
3440 qemu_deviceadd
($vmid, $netdevicefull);
3441 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3443 eval { qemu_netdevdel
($vmid, $deviceid); };
3448 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
3451 my $pciaddr = print_pci_addr
($deviceid);
3452 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
3454 qemu_deviceadd
($vmid, $devicefull);
3455 qemu_deviceaddverify
($vmid, $deviceid);
3458 die "can't hotplug device '$deviceid'\n";
3464 # fixme: this should raise exceptions on error!
3465 sub vm_deviceunplug
{
3466 my ($vmid, $conf, $deviceid) = @_;
3468 my $devices_list = vm_devices_list
($vmid);
3469 return 1 if !defined($devices_list->{$deviceid});
3471 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
3473 if ($deviceid eq 'tablet') {
3475 qemu_devicedel
($vmid, $deviceid);
3477 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3479 qemu_devicedel
($vmid, $deviceid);
3480 qemu_devicedelverify
($vmid, $deviceid);
3481 qemu_drivedel
($vmid, $deviceid);
3482 qemu_iothread_del
($conf, $vmid, $deviceid);
3484 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3486 qemu_devicedel
($vmid, $deviceid);
3487 qemu_devicedelverify
($vmid, $deviceid);
3488 qemu_iothread_del
($conf, $vmid, $deviceid);
3490 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3492 #qemu 2.3 segfault on drive_del with virtioscsi + iothread
3493 my $device = parse_drive
($deviceid, $conf->{$deviceid});
3494 die "virtioscsi with iothread is not hot-unplugglable currently" if $device->{iothread
};
3496 qemu_devicedel
($vmid, $deviceid);
3497 qemu_drivedel
($vmid, $deviceid);
3498 qemu_deletescsihw
($conf, $vmid, $deviceid);
3500 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3502 qemu_devicedel
($vmid, $deviceid);
3503 qemu_devicedelverify
($vmid, $deviceid);
3504 qemu_netdevdel
($vmid, $deviceid);
3507 die "can't unplug device '$deviceid'\n";
3513 sub qemu_deviceadd
{
3514 my ($vmid, $devicefull) = @_;
3516 $devicefull = "driver=".$devicefull;
3517 my %options = split(/[=,]/, $devicefull);
3519 vm_mon_cmd
($vmid, "device_add" , %options);
3522 sub qemu_devicedel
{
3523 my ($vmid, $deviceid) = @_;
3525 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
3528 sub qemu_iothread_add
{
3529 my($vmid, $deviceid, $device) = @_;
3531 if ($device->{iothread
}) {
3532 my $iothreads = vm_iothreads_list
($vmid);
3533 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
3537 sub qemu_iothread_del
{
3538 my($conf, $vmid, $deviceid) = @_;
3540 my $device = parse_drive
($deviceid, $conf->{$deviceid});
3541 if ($device->{iothread
}) {
3542 my $iothreads = vm_iothreads_list
($vmid);
3543 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
3547 sub qemu_objectadd
{
3548 my($vmid, $objectid, $qomtype) = @_;
3550 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
3555 sub qemu_objectdel
{
3556 my($vmid, $objectid) = @_;
3558 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
3564 my ($storecfg, $vmid, $device) = @_;
3566 my $drive = print_drive_full
($storecfg, $vmid, $device);
3567 $drive =~ s/\\/\\\\/g;
3568 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
3570 # If the command succeeds qemu prints: "OK
"
3571 return 1 if $ret =~ m/OK/s;
3573 die "adding drive failed
: $ret\n";
3577 my($vmid, $deviceid) = @_;
3579 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
3582 return 1 if $ret eq "";
3584 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
3585 return 1 if $ret =~ m/Device \'.*?\' not found/s;
3587 die "deleting drive
$deviceid failed
: $ret\n";
3590 sub qemu_deviceaddverify {
3591 my ($vmid, $deviceid) = @_;
3593 for (my $i = 0; $i <= 5; $i++) {
3594 my $devices_list = vm_devices_list($vmid);
3595 return 1 if defined($devices_list->{$deviceid});
3599 die "error on hotplug device
'$deviceid'\n";
3603 sub qemu_devicedelverify {
3604 my ($vmid, $deviceid) = @_;
3606 # need to verify that the device is correctly removed as device_del
3607 # is async and empty return is not reliable
3609 for (my $i = 0; $i <= 5; $i++) {
3610 my $devices_list = vm_devices_list($vmid);
3611 return 1 if !defined($devices_list->{$deviceid});
3615 die "error on hot-unplugging device
'$deviceid'\n";
3618 sub qemu_findorcreatescsihw {
3619 my ($storecfg, $conf, $vmid, $device) = @_;
3621 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3623 my $scsihwid="$controller_prefix$controller";
3624 my $devices_list = vm_devices_list($vmid);
3626 if(!defined($devices_list->{$scsihwid})) {
3627 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device);
3633 sub qemu_deletescsihw {
3634 my ($conf, $vmid, $opt) = @_;
3636 my $device = parse_drive($opt, $conf->{$opt});
3638 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
3639 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
3643 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3645 my $devices_list = vm_devices_list($vmid);
3646 foreach my $opt (keys %{$devices_list}) {
3647 if (PVE::QemuServer::is_valid_drivename($opt)) {
3648 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
3649 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
3655 my $scsihwid="scsihw
$controller";
3657 vm_deviceunplug($vmid, $conf, $scsihwid);
3662 sub qemu_add_pci_bridge {
3663 my ($storecfg, $conf, $vmid, $device) = @_;
3669 print_pci_addr($device, $bridges);
3671 while (my ($k, $v) = each %$bridges) {
3674 return 1 if !defined($bridgeid) || $bridgeid < 1;
3676 my $bridge = "pci
.$bridgeid";
3677 my $devices_list = vm_devices_list($vmid);
3679 if (!defined($devices_list->{$bridge})) {
3680 vm_deviceplug($storecfg, $conf, $vmid, $bridge);
3686 sub qemu_set_link_status {
3687 my ($vmid, $device, $up) = @_;
3689 vm_mon_cmd($vmid, "set_link
", name => $device,
3690 up => $up ? JSON::true : JSON::false);
3693 sub qemu_netdevadd {
3694 my ($vmid, $conf, $device, $deviceid) = @_;
3696 my $netdev = print_netdev_full($vmid, $conf, $device, $deviceid, 1);
3697 my %options = split(/[=,]/, $netdev);
3699 vm_mon_cmd($vmid, "netdev_add
", %options);
3703 sub qemu_netdevdel {
3704 my ($vmid, $deviceid) = @_;
3706 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
3709 sub qemu_cpu_hotplug {
3710 my ($vmid, $conf, $vcpus) = @_;
3713 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
3714 $sockets = $conf->{sockets} if $conf->{sockets};
3715 my $cores = $conf->{cores} || 1;
3716 my $maxcpus = $sockets * $cores;
3718 $vcpus = $maxcpus if !$vcpus;
3720 die "you can
't add more vcpus than maxcpus\n"
3721 if $vcpus > $maxcpus;
3723 my $currentvcpus = $conf->{vcpus} || $maxcpus;
3724 die "online cpu unplug is not yet possible\n"
3725 if $vcpus < $currentvcpus;
3727 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
3728 die "vcpus in running vm is different than configuration\n"
3729 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
3731 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
3732 vm_mon_cmd($vmid, "cpu-add", id => int($i));
3736 sub qemu_memory_hotplug {
3737 my ($vmid, $conf, $defaults, $opt, $value) = @_;
3739 return $value if !check_running($vmid);
3741 my $memory = $conf->{memory} || $defaults->{memory};
3742 $value = $defaults->{memory} if !$value;
3743 return $value if $value == $memory;
3745 my $static_memory = $STATICMEM;
3746 my $dimm_memory = $memory - $static_memory;
3748 die "memory can't be lower than
$static_memory MB
" if $value < $static_memory;
3749 die "you cannot add more memory than
$MAX_MEM MB
!\n" if $memory > $MAX_MEM;
3753 $sockets = $conf->{sockets} if $conf->{sockets};
3755 if($value > $memory) {
3757 foreach_dimm($conf, $vmid, $value, $sockets, sub {
3758 my ($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory) = @_;
3760 return if $current_size <= $conf->{memory};
3762 eval { vm_mon_cmd($vmid, "object-add
", 'qom-type' => "memory-backend-ram
", id => "mem-
$name", props => { size => int($dimm_size*1024*1024) } ) };
3764 eval { qemu_objectdel($vmid, "mem-
$name"); };
3768 eval { vm_mon_cmd($vmid, "device_add
", driver => "pc-dimm
", id => "$name", memdev => "mem-
$name", node => $numanode) };
3770 eval { qemu_objectdel($vmid, "mem-
$name"); };
3773 #update conf after each succesful module hotplug
3774 $conf->{memory} = $current_size;
3775 PVE::QemuConfig->write_config($vmid, $conf);
3780 foreach_reverse_dimm($conf, $vmid, $value, $sockets, sub {
3781 my ($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory) = @_;
3783 return if $current_size >= $conf->{memory};
3784 print "try to unplug memory dimm
$name\n";
3788 eval { qemu_devicedel($vmid, $name) };
3790 my $dimm_list = qemu_dimm_list($vmid);
3791 last if !$dimm_list->{$name};
3792 raise_param_exc({ $name => "error unplug memory module
" }) if $retry > 5;
3796 #update conf after each succesful module unplug
3797 $conf->{memory} = $current_size;
3799 eval { qemu_objectdel($vmid, "mem-
$name"); };
3800 PVE::QemuConfig->write_config($vmid, $conf);
3805 sub qemu_dimm_list {
3808 my $dimmarray = vm_mon_cmd_nocheck($vmid, "query-memory-devices
");
3811 foreach my $dimm (@$dimmarray) {
3813 $dimms->{$dimm->{data}->{id}}->{id} = $dimm->{data}->{id};
3814 $dimms->{$dimm->{data}->{id}}->{node} = $dimm->{data}->{node};
3815 $dimms->{$dimm->{data}->{id}}->{addr} = $dimm->{data}->{addr};
3816 $dimms->{$dimm->{data}->{id}}->{size} = $dimm->{data}->{size};
3817 $dimms->{$dimm->{data}->{id}}->{slot} = $dimm->{data}->{slot};
3822 sub qemu_block_set_io_throttle {
3823 my ($vmid, $deviceid,
3824 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
3825 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max) = @_;
3827 return if !check_running($vmid) ;
3829 vm_mon_cmd($vmid, "block_set_io_throttle
", device => $deviceid,
3831 bps_rd => int($bps_rd),
3832 bps_wr => int($bps_wr),
3834 iops_rd => int($iops_rd),
3835 iops_wr => int($iops_wr),
3836 bps_max => int($bps_max),
3837 bps_rd_max => int($bps_rd_max),
3838 bps_wr_max => int($bps_wr_max),
3839 iops_max => int($iops_max),
3840 iops_rd_max => int($iops_rd_max),
3841 iops_wr_max => int($iops_wr_max)
3846 # old code, only used to shutdown old VM after update
3848 my ($fh, $timeout) = @_;
3850 my $sel = new IO::Select;
3857 while (scalar (@ready = $sel->can_read($timeout))) {
3859 if ($count = $fh->sysread($buf, 8192)) {
3860 if ($buf =~ /^(.*)\(qemu\) $/s) {
3867 if (!defined($count)) {
3874 die "monitor
read timeout
\n" if !scalar(@ready);
3879 # old code, only used to shutdown old VM after update
3880 sub vm_monitor_command {
3881 my ($vmid, $cmdstr, $nocheck) = @_;
3886 die "VM
$vmid not running
\n" if !check_running($vmid, $nocheck);
3888 my $sname = "${var_run_tmpdir
}/$vmid.mon
";
3890 my $sock = IO::Socket::UNIX->new( Peer => $sname ) ||
3891 die "unable to
connect to VM
$vmid socket - $!\n";
3895 # hack: migrate sometime blocks the monitor (when migrate_downtime
3897 if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
3898 $timeout = 60*60; # 1 hour
3902 my $data = __read_avail($sock, $timeout);
3904 if ($data !~ m/^QEMU\s+(\S+)\s+monitor\s/) {
3905 die "got unexpected qemu monitor banner
\n";
3908 my $sel = new IO::Select;
3911 if (!scalar(my @ready = $sel->can_write($timeout))) {
3912 die "monitor
write error
- timeout
";
3915 my $fullcmd = "$cmdstr\r";
3917 # syslog('info', "VM
$vmid monitor command
: $cmdstr");
3920 if (!($b = $sock->syswrite($fullcmd)) || ($b != length($fullcmd))) {
3921 die "monitor
write error
- $!";
3924 return if ($cmdstr eq 'q') || ($cmdstr eq 'quit');
3928 if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
3929 $timeout = 60*60; # 1 hour
3930 } elsif ($cmdstr =~ m/^(eject|change)/) {
3931 $timeout = 60; # note: cdrom mount command is slow
3933 if ($res = __read_avail($sock, $timeout)) {
3935 my @lines = split("\r?
\n", $res);
3937 shift @lines if $lines[0] !~ m/^unknown command/; # skip echo
3939 $res = join("\n", @lines);
3947 syslog("err
", "VM
$vmid monitor command failed
- $err");
3954 sub qemu_block_resize {
3955 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
3957 my $running = check_running($vmid);
3959 return if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
3961 return if !$running;
3963 vm_mon_cmd($vmid, "block_resize
", device => $deviceid, size => int($size));
3967 sub qemu_volume_snapshot {
3968 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
3970 my $running = check_running($vmid);
3972 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
3973 vm_mon_cmd($vmid, "snapshot-drive
", device => $deviceid, name => $snap);
3975 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
3979 sub qemu_volume_snapshot_delete {
3980 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
3982 my $running = check_running($vmid);
3984 return if !PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
3986 return if !$running;
3988 vm_mon_cmd($vmid, "delete-drive-snapshot
", device => $deviceid, name => $snap);
3991 sub set_migration_caps {
3997 "auto-converge
" => 1,
3999 "x-rdma-pin-all
" => 0,
4004 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities
");
4006 for my $supported_capability (@$supported_capabilities) {
4008 capability => $supported_capability->{capability},
4009 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4013 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities
", capabilities => $cap_ref);
4016 my $fast_plug_option = {
4025 # hotplug changes in [PENDING]
4026 # $selection hash can be used to only apply specified options, for
4027 # example: { cores => 1 } (only apply changed 'cores')
4028 # $errors ref is used to return error messages
4029 sub vmconfig_hotplug_pending {
4030 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4032 my $defaults = load_defaults();
4034 # commit values which do not have any impact on running VM first
4035 # Note: those option cannot raise errors, we we do not care about
4036 # $selection and always apply them.
4038 my $add_error = sub {
4039 my ($opt, $msg) = @_;
4040 $errors->{$opt} = "hotplug problem
- $msg";
4044 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4045 if ($fast_plug_option->{$opt}) {
4046 $conf->{$opt} = $conf->{pending}->{$opt};
4047 delete $conf->{pending}->{$opt};
4053 PVE::QemuConfig->write_config($vmid, $conf);
4054 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4057 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4059 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4060 while (my ($opt, $force) = each %$pending_delete_hash) {
4061 next if $selection && !$selection->{$opt};
4063 if ($opt eq 'hotplug') {
4064 die "skip
\n" if ($conf->{hotplug} =~ /memory/);
4065 } elsif ($opt eq 'tablet') {
4066 die "skip
\n" if !$hotplug_features->{usb};
4067 if ($defaults->{tablet}) {
4068 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4070 vm_deviceunplug($vmid, $conf, $opt);
4072 } elsif ($opt eq 'vcpus') {
4073 die "skip
\n" if !$hotplug_features->{cpu};
4074 qemu_cpu_hotplug($vmid, $conf, undef);
4075 } elsif ($opt eq 'balloon') {
4076 # enable balloon device is not hotpluggable
4077 die "skip
\n" if !defined($conf->{balloon}) || $conf->{balloon};
4078 } elsif ($fast_plug_option->{$opt}) {
4080 } elsif ($opt =~ m/^net(\d+)$/) {
4081 die "skip
\n" if !$hotplug_features->{network};
4082 vm_deviceunplug($vmid, $conf, $opt);
4083 } elsif (is_valid_drivename($opt)) {
4084 die "skip
\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4085 vm_deviceunplug($vmid, $conf, $opt);
4086 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4087 } elsif ($opt =~ m/^memory$/) {
4088 die "skip
\n" if !$hotplug_features->{memory};
4089 qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4090 } elsif ($opt eq 'cpuunits') {
4091 cgroups_write("cpu
", $vmid, "cpu
.shares
", $defaults->{cpuunits});
4092 } elsif ($opt eq 'cpulimit') {
4093 cgroups_write("cpu
", $vmid, "cpu
.cfs_quota_us
", -1);
4099 &$add_error($opt, $err) if $err ne "skip
\n";
4101 # save new config if hotplug was successful
4102 delete $conf->{$opt};
4103 vmconfig_undelete_pending_option($conf, $opt);
4104 PVE::QemuConfig->write_config($vmid, $conf);
4105 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4109 foreach my $opt (keys %{$conf->{pending}}) {
4110 next if $selection && !$selection->{$opt};
4111 my $value = $conf->{pending}->{$opt};
4113 if ($opt eq 'hotplug') {
4114 die "skip
\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4115 } elsif ($opt eq 'tablet') {
4116 die "skip
\n" if !$hotplug_features->{usb};
4118 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4119 } elsif ($value == 0) {
4120 vm_deviceunplug($vmid, $conf, $opt);
4122 } elsif ($opt eq 'vcpus') {
4123 die "skip
\n" if !$hotplug_features->{cpu};
4124 qemu_cpu_hotplug($vmid, $conf, $value);
4125 } elsif ($opt eq 'balloon') {
4126 # enable/disable balloning device is not hotpluggable
4127 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4128 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4129 die "skip
\n" if $old_balloon_enabled != $new_balloon_enabled;
4131 # allow manual ballooning if shares is set to zero
4132 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4133 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4134 vm_mon_cmd($vmid, "balloon
", value => $balloon*1024*1024);
4136 } elsif ($opt =~ m/^net(\d+)$/) {
4137 # some changes can be done without hotplug
4138 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4139 $vmid, $opt, $value);
4140 } elsif (is_valid_drivename($opt)) {
4141 # some changes can be done without hotplug
4142 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4143 $vmid, $opt, $value, 1);
4144 } elsif ($opt =~ m/^memory$/) { #dimms
4145 die "skip
\n" if !$hotplug_features->{memory};
4146 $value = qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4147 } elsif ($opt eq 'cpuunits') {
4148 cgroups_write("cpu
", $vmid, "cpu
.shares
", $conf->{pending}->{$opt});
4149 } elsif ($opt eq 'cpulimit') {
4150 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4151 cgroups_write("cpu
", $vmid, "cpu
.cfs_quota_us
", $cpulimit);
4153 die "skip
\n"; # skip non-hot-pluggable options
4157 &$add_error($opt, $err) if $err ne "skip
\n";
4159 # save new config if hotplug was successful
4160 $conf->{$opt} = $value;
4161 delete $conf->{pending}->{$opt};
4162 PVE::QemuConfig->write_config($vmid, $conf);
4163 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4168 sub try_deallocate_drive {
4169 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4171 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4172 my $volid = $drive->{file};
4173 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4174 my $sid = PVE::Storage::parse_volume_id($volid);
4175 $rpcenv->check($authuser, "/storage/$sid", ['Datastore.AllocateSpace']);
4177 # check if the disk is really unused
4178 die "unable to
delete '$volid' - volume
is still
in use (snapshot?
)\n"
4179 if is_volume_in_use($storecfg, $conf, $key, $volid);
4180 PVE::Storage::vdisk_free($storecfg, $volid);
4183 # If vm is not owner of this disk remove from config
4191 sub vmconfig_delete_or_detach_drive {
4192 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4194 my $drive = parse_drive($opt, $conf->{$opt});
4196 my $rpcenv = PVE::RPCEnvironment::get();
4197 my $authuser = $rpcenv->get_user();
4200 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.Disk']);
4201 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4203 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4207 sub vmconfig_apply_pending {
4208 my ($vmid, $conf, $storecfg) = @_;
4212 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4213 while (my ($opt, $force) = each %$pending_delete_hash) {
4214 die "internal error
" if $opt =~ m/^unused/;
4215 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4216 if (!defined($conf->{$opt})) {
4217 vmconfig_undelete_pending_option($conf, $opt);
4218 PVE::QemuConfig->write_config($vmid, $conf);
4219 } elsif (is_valid_drivename($opt)) {
4220 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4221 vmconfig_undelete_pending_option($conf, $opt);
4222 delete $conf->{$opt};
4223 PVE::QemuConfig->write_config($vmid, $conf);
4225 vmconfig_undelete_pending_option($conf, $opt);
4226 delete $conf->{$opt};
4227 PVE::QemuConfig->write_config($vmid, $conf);
4231 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4233 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4234 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4236 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4237 # skip if nothing changed
4238 } elsif (is_valid_drivename($opt)) {
4239 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4240 if defined($conf->{$opt});
4241 $conf->{$opt} = $conf->{pending}->{$opt};
4243 $conf->{$opt} = $conf->{pending}->{$opt};
4246 delete $conf->{pending}->{$opt};
4247 PVE::QemuConfig->write_config($vmid, $conf);
4251 my $safe_num_ne = sub {
4254 return 0 if !defined($a) && !defined($b);
4255 return 1 if !defined($a);
4256 return 1 if !defined($b);
4261 my $safe_string_ne = sub {
4264 return 0 if !defined($a) && !defined($b);
4265 return 1 if !defined($a);
4266 return 1 if !defined($b);
4271 sub vmconfig_update_net {
4272 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value) = @_;
4274 my $newnet = parse_net($value);
4276 if ($conf->{$opt}) {
4277 my $oldnet = parse_net($conf->{$opt});
4279 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4280 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4281 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4282 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4284 # for non online change, we try to hot-unplug
4285 die "skip
\n" if !$hotplug;
4286 vm_deviceunplug($vmid, $conf, $opt);
4289 die "internal error
" if $opt !~ m/net(\d+)/;
4290 my $iface = "tap
${vmid
}i
$1";
4292 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4293 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4294 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4295 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4296 PVE::Network::tap_unplug($iface);
4297 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4298 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4299 # Rate can be applied on its own but any change above needs to
4300 # include the rate in tap_plug since OVS resets everything.
4301 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4304 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4305 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4313 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet);
4319 sub vmconfig_update_disk {
4320 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force) = @_;
4322 # fixme: do we need force?
4324 my $drive = parse_drive($opt, $value);
4326 if ($conf->{$opt}) {
4328 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4330 my $media = $drive->{media} || 'disk';
4331 my $oldmedia = $old_drive->{media} || 'disk';
4332 die "unable to change media type
\n" if $media ne $oldmedia;
4334 if (!drive_is_cdrom($old_drive)) {
4336 if ($drive->{file} ne $old_drive->{file}) {
4338 die "skip
\n" if !$hotplug;
4340 # unplug and register as unused
4341 vm_deviceunplug($vmid, $conf, $opt);
4342 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4345 # update existing disk
4347 # skip non hotpluggable value
4348 if (&$safe_num_ne($drive->{discard}, $old_drive->{discard}) ||
4349 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4350 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4351 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
4356 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4357 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4358 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4359 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4360 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4361 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4362 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4363 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4364 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4365 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4366 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4367 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max})) {
4369 qemu_block_set_io_throttle($vmid,"drive-
$opt",
4370 ($drive->{mbps} || 0)*1024*1024,
4371 ($drive->{mbps_rd} || 0)*1024*1024,
4372 ($drive->{mbps_wr} || 0)*1024*1024,
4373 $drive->{iops} || 0,
4374 $drive->{iops_rd} || 0,
4375 $drive->{iops_wr} || 0,
4376 ($drive->{mbps_max} || 0)*1024*1024,
4377 ($drive->{mbps_rd_max} || 0)*1024*1024,
4378 ($drive->{mbps_wr_max} || 0)*1024*1024,
4379 $drive->{iops_max} || 0,
4380 $drive->{iops_rd_max} || 0,
4381 $drive->{iops_wr_max} || 0);
4390 if ($drive->{file} eq 'none') {
4391 vm_mon_cmd($vmid, "eject
",force => JSON::true,device => "drive-
$opt");
4393 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4394 vm_mon_cmd($vmid, "eject
", force => JSON::true,device => "drive-
$opt"); # force eject if locked
4395 vm_mon_cmd($vmid, "change
", device => "drive-
$opt",target => "$path") if $path;
4403 die "skip
\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4405 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
4406 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive);
4410 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
4411 $forcemachine, $spice_ticket) = @_;
4413 PVE::QemuConfig->lock_config($vmid, sub {
4414 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
4416 die "you can
't start a vm if it's a template
\n" if PVE::QemuConfig->is_template($conf);
4418 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4420 die "VM
$vmid already running
\n" if check_running($vmid, undef, $migratedfrom);
4422 if (!$statefile && scalar(keys %{$conf->{pending}})) {
4423 vmconfig_apply_pending($vmid, $conf, $storecfg);
4424 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4427 my $defaults = load_defaults();
4429 # set environment variable useful inside network script
4430 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
4432 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
4434 my $migrate_port = 0;
4437 if ($statefile eq 'tcp') {
4438 my $localip = "localhost
";
4439 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter.cfg');
4440 my $nodename = PVE::INotify::nodename();
4441 if ($datacenterconf->{migration_unsecure}) {
4442 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
4443 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4445 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4446 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4447 $migrate_uri = "tcp
:${localip
}:${migrate_port
}";
4448 push @$cmd, '-incoming', $migrate_uri;
4451 push @$cmd, '-loadstate', $statefile;
4458 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
4459 my $d = parse_hostpci($conf->{"hostpci
$i"});
4461 my $pcidevices = $d->{pciid};
4462 foreach my $pcidevice (@$pcidevices) {
4463 my $pciid = $pcidevice->{id}.".".$pcidevice->{function};
4465 my $info = pci_device_info("0000:$pciid");
4466 die "IOMMU
not present
\n" if !check_iommu_support();
4467 die "no pci device info
for device
'$pciid'\n" if !$info;
4468 die "can
't unbind/bind pci group to vfio '$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
4469 die "can't
reset pci device
'$pciid'\n" if $info->{has_fl_reset} and !pci_dev_reset($info);
4473 PVE::Storage::activate_volumes($storecfg, $vollist);
4475 eval { run_command($cmd, timeout => $statefile ? undef : 30,
4479 # deactivate volumes if start fails
4480 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
4481 die "start failed
: $err";
4484 print "migration listens on
$migrate_uri\n" if $migrate_uri;
4486 if ($statefile && $statefile ne 'tcp') {
4487 eval { vm_mon_cmd_nocheck($vmid, "cont
"); };
4491 if ($migratedfrom) {
4494 set_migration_caps($vmid);
4499 print "spice listens on port
$spice_port\n";
4500 if ($spice_ticket) {
4501 vm_mon_cmd_nocheck($vmid, "set_password
", protocol => 'spice', password => $spice_ticket);
4502 vm_mon_cmd_nocheck($vmid, "expire_password
", protocol => 'spice', time => "+30");
4508 if (!$statefile && (!defined($conf->{balloon}) || $conf->{balloon})) {
4509 vm_mon_cmd_nocheck($vmid, "balloon
", value => $conf->{balloon}*1024*1024)
4510 if $conf->{balloon};
4513 foreach my $opt (keys %$conf) {
4514 next if $opt !~ m/^net\d+$/;
4515 my $nicconf = parse_net($conf->{$opt});
4516 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
4520 vm_mon_cmd_nocheck($vmid, 'qom-set',
4521 path => "machine
/peripheral/balloon0
",
4522 property => "guest-stats-polling-interval
",
4523 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
4529 my ($vmid, $execute, %params) = @_;
4531 my $cmd = { execute => $execute, arguments => \%params };
4532 vm_qmp_command($vmid, $cmd);
4535 sub vm_mon_cmd_nocheck {
4536 my ($vmid, $execute, %params) = @_;
4538 my $cmd = { execute => $execute, arguments => \%params };
4539 vm_qmp_command($vmid, $cmd, 1);
4542 sub vm_qmp_command {
4543 my ($vmid, $cmd, $nocheck) = @_;
4548 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
4549 $timeout = $cmd->{arguments}->{timeout};
4550 delete $cmd->{arguments}->{timeout};
4554 die "VM
$vmid not running
\n" if !check_running($vmid, $nocheck);
4555 my $sname = qmp_socket($vmid);
4556 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
4557 my $qmpclient = PVE::QMPClient->new();
4559 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
4560 } elsif (-e "${var_run_tmpdir
}/$vmid.mon
") {
4561 die "can
't execute complex command on old monitor - stop/start your vm to fix the problem\n"
4562 if scalar(%{$cmd->{arguments}});
4563 vm_monitor_command($vmid, $cmd->{execute}, $nocheck);
4565 die "unable to open monitor socket\n";
4569 syslog("err", "VM $vmid qmp command failed - $err");
4576 sub vm_human_monitor_command {
4577 my ($vmid, $cmdline) = @_;
4582 execute => 'human-monitor-command
',
4583 arguments => { 'command-line
' => $cmdline},
4586 return vm_qmp_command($vmid, $cmd);
4589 sub vm_commandline {
4590 my ($storecfg, $vmid) = @_;
4592 my $conf = PVE::QemuConfig->load_config($vmid);
4594 my $defaults = load_defaults();
4596 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
4598 return join(' ', @$cmd);
4602 my ($vmid, $skiplock) = @_;
4604 PVE::QemuConfig->lock_config($vmid, sub {
4606 my $conf = PVE::QemuConfig->load_config($vmid);
4608 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4610 vm_mon_cmd($vmid, "system_reset");
4614 sub get_vm_volumes {
4618 foreach_volid($conf, sub {
4619 my ($volid, $is_cdrom) = @_;
4621 return if $volid =~ m|^/|;
4623 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
4626 push @$vollist, $volid;
4632 sub vm_stop_cleanup {
4633 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
4638 my $vollist = get_vm_volumes($conf);
4639 PVE::Storage::deactivate_volumes($storecfg, $vollist);
4642 foreach my $ext (qw(mon qmp pid vnc qga)) {
4643 unlink "/var/run/qemu-server/${vmid}.$ext";
4646 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
4648 warn $@ if $@; # avoid errors - just warn
4651 # Note: use $nockeck to skip tests if VM configuration file exists.
4652 # We need that when migration VMs to other nodes (files already moved)
4653 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
4655 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
4657 $force = 1 if !defined($force) && !$shutdown;
4660 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
4661 kill 15, $pid if $pid;
4662 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
4663 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
4667 PVE
::QemuConfig-
>lock_config($vmid, sub {
4669 my $pid = check_running
($vmid, $nocheck);
4674 $conf = PVE
::QemuConfig-
>load_config($vmid);
4675 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
4676 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
4677 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
4678 $timeout = $opts->{down
} if $opts->{down
};
4682 $timeout = 60 if !defined($timeout);
4686 if (defined($conf) && $conf->{agent
}) {
4687 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
4689 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
4692 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
4699 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
4704 if ($count >= $timeout) {
4706 warn "VM still running - terminating now with SIGTERM\n";
4709 die "VM quit/powerdown failed - got timeout\n";
4712 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
4717 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
4720 die "VM quit/powerdown failed\n";
4728 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
4733 if ($count >= $timeout) {
4734 warn "VM still running - terminating now with SIGKILL\n";
4739 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
4744 my ($vmid, $skiplock) = @_;
4746 PVE
::QemuConfig-
>lock_config($vmid, sub {
4748 my $conf = PVE
::QemuConfig-
>load_config($vmid);
4750 PVE
::QemuConfig-
>check_lock($conf)
4751 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
4753 vm_mon_cmd
($vmid, "stop");
4758 my ($vmid, $skiplock, $nocheck) = @_;
4760 PVE
::QemuConfig-
>lock_config($vmid, sub {
4764 my $conf = PVE
::QemuConfig-
>load_config($vmid);
4766 PVE
::QemuConfig-
>check_lock($conf)
4767 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
4769 vm_mon_cmd
($vmid, "cont");
4772 vm_mon_cmd_nocheck
($vmid, "cont");
4778 my ($vmid, $skiplock, $key) = @_;
4780 PVE
::QemuConfig-
>lock_config($vmid, sub {
4782 my $conf = PVE
::QemuConfig-
>load_config($vmid);
4784 # there is no qmp command, so we use the human monitor command
4785 vm_human_monitor_command
($vmid, "sendkey $key");
4790 my ($storecfg, $vmid, $skiplock) = @_;
4792 PVE
::QemuConfig-
>lock_config($vmid, sub {
4794 my $conf = PVE
::QemuConfig-
>load_config($vmid);
4796 if (!check_running
($vmid)) {
4797 destroy_vm
($storecfg, $vmid, undef, $skiplock);
4799 die "VM $vmid is running - destroy failed\n";
4807 my ($filename, $buf) = @_;
4809 my $fh = IO
::File-
>new($filename, "w");
4810 return undef if !$fh;
4812 my $res = print $fh $buf;
4819 sub pci_device_info
{
4824 return undef if $name !~ m/^([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\.([a-f0-9])$/;
4825 my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4);
4827 my $irq = file_read_firstline
("$pcisysfs/devices/$name/irq");
4828 return undef if !defined($irq) || $irq !~ m/^\d+$/;
4830 my $vendor = file_read_firstline
("$pcisysfs/devices/$name/vendor");
4831 return undef if !defined($vendor) || $vendor !~ s/^0x//;
4833 my $product = file_read_firstline
("$pcisysfs/devices/$name/device");
4834 return undef if !defined($product) || $product !~ s/^0x//;
4839 product
=> $product,
4845 has_fl_reset
=> -f
"$pcisysfs/devices/$name/reset" || 0,
4854 my $name = $dev->{name
};
4856 my $fn = "$pcisysfs/devices/$name/reset";
4858 return file_write
($fn, "1");
4861 sub pci_dev_bind_to_vfio
{
4864 my $name = $dev->{name
};
4866 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
4868 if (!-d
$vfio_basedir) {
4869 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
4871 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
4873 my $testdir = "$vfio_basedir/$name";
4874 return 1 if -d
$testdir;
4876 my $data = "$dev->{vendor} $dev->{product}";
4877 return undef if !file_write
("$vfio_basedir/new_id", $data);
4879 my $fn = "$pcisysfs/devices/$name/driver/unbind";
4880 if (!file_write
($fn, $name)) {
4881 return undef if -f
$fn;
4884 $fn = "$vfio_basedir/bind";
4885 if (! -d
$testdir) {
4886 return undef if !file_write
($fn, $name);
4892 sub pci_dev_group_bind_to_vfio
{
4895 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
4897 if (!-d
$vfio_basedir) {
4898 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
4900 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
4902 # get IOMMU group devices
4903 opendir(my $D, "$pcisysfs/devices/0000:$pciid/iommu_group/devices/") || die "Cannot open iommu_group: $!\n";
4904 my @devs = grep /^0000:/, readdir($D);
4907 foreach my $pciid (@devs) {
4908 $pciid =~ m/^([:\.\da-f]+)$/ or die "PCI ID $pciid not valid!\n";
4910 # pci bridges, switches or root ports are not supported
4911 # they have a pci_bus subdirectory so skip them
4912 next if (-e
"$pcisysfs/devices/$pciid/pci_bus");
4914 my $info = pci_device_info
($1);
4915 pci_dev_bind_to_vfio
($info) || die "Cannot bind $pciid to vfio\n";
4921 sub print_pci_addr
{
4922 my ($id, $bridges) = @_;
4926 piix3
=> { bus
=> 0, addr
=> 1 },
4927 #addr2 : first videocard
4928 balloon0
=> { bus
=> 0, addr
=> 3 },
4929 watchdog
=> { bus
=> 0, addr
=> 4 },
4930 scsihw0
=> { bus
=> 0, addr
=> 5 },
4931 'pci.3' => { bus
=> 0, addr
=> 5 }, #can also be used for virtio-scsi-single bridge
4932 scsihw1
=> { bus
=> 0, addr
=> 6 },
4933 ahci0
=> { bus
=> 0, addr
=> 7 },
4934 qga0
=> { bus
=> 0, addr
=> 8 },
4935 spice
=> { bus
=> 0, addr
=> 9 },
4936 virtio0
=> { bus
=> 0, addr
=> 10 },
4937 virtio1
=> { bus
=> 0, addr
=> 11 },
4938 virtio2
=> { bus
=> 0, addr
=> 12 },
4939 virtio3
=> { bus
=> 0, addr
=> 13 },
4940 virtio4
=> { bus
=> 0, addr
=> 14 },
4941 virtio5
=> { bus
=> 0, addr
=> 15 },
4942 hostpci0
=> { bus
=> 0, addr
=> 16 },
4943 hostpci1
=> { bus
=> 0, addr
=> 17 },
4944 net0
=> { bus
=> 0, addr
=> 18 },
4945 net1
=> { bus
=> 0, addr
=> 19 },
4946 net2
=> { bus
=> 0, addr
=> 20 },
4947 net3
=> { bus
=> 0, addr
=> 21 },
4948 net4
=> { bus
=> 0, addr
=> 22 },
4949 net5
=> { bus
=> 0, addr
=> 23 },
4950 vga1
=> { bus
=> 0, addr
=> 24 },
4951 vga2
=> { bus
=> 0, addr
=> 25 },
4952 vga3
=> { bus
=> 0, addr
=> 26 },
4953 hostpci2
=> { bus
=> 0, addr
=> 27 },
4954 hostpci3
=> { bus
=> 0, addr
=> 28 },
4955 #addr29 : usb-host (pve-usb.cfg)
4956 'pci.1' => { bus
=> 0, addr
=> 30 },
4957 'pci.2' => { bus
=> 0, addr
=> 31 },
4958 'net6' => { bus
=> 1, addr
=> 1 },
4959 'net7' => { bus
=> 1, addr
=> 2 },
4960 'net8' => { bus
=> 1, addr
=> 3 },
4961 'net9' => { bus
=> 1, addr
=> 4 },
4962 'net10' => { bus
=> 1, addr
=> 5 },
4963 'net11' => { bus
=> 1, addr
=> 6 },
4964 'net12' => { bus
=> 1, addr
=> 7 },
4965 'net13' => { bus
=> 1, addr
=> 8 },
4966 'net14' => { bus
=> 1, addr
=> 9 },
4967 'net15' => { bus
=> 1, addr
=> 10 },
4968 'net16' => { bus
=> 1, addr
=> 11 },
4969 'net17' => { bus
=> 1, addr
=> 12 },
4970 'net18' => { bus
=> 1, addr
=> 13 },
4971 'net19' => { bus
=> 1, addr
=> 14 },
4972 'net20' => { bus
=> 1, addr
=> 15 },
4973 'net21' => { bus
=> 1, addr
=> 16 },
4974 'net22' => { bus
=> 1, addr
=> 17 },
4975 'net23' => { bus
=> 1, addr
=> 18 },
4976 'net24' => { bus
=> 1, addr
=> 19 },
4977 'net25' => { bus
=> 1, addr
=> 20 },
4978 'net26' => { bus
=> 1, addr
=> 21 },
4979 'net27' => { bus
=> 1, addr
=> 22 },
4980 'net28' => { bus
=> 1, addr
=> 23 },
4981 'net29' => { bus
=> 1, addr
=> 24 },
4982 'net30' => { bus
=> 1, addr
=> 25 },
4983 'net31' => { bus
=> 1, addr
=> 26 },
4984 'xhci' => { bus
=> 1, addr
=> 27 },
4985 'virtio6' => { bus
=> 2, addr
=> 1 },
4986 'virtio7' => { bus
=> 2, addr
=> 2 },
4987 'virtio8' => { bus
=> 2, addr
=> 3 },
4988 'virtio9' => { bus
=> 2, addr
=> 4 },
4989 'virtio10' => { bus
=> 2, addr
=> 5 },
4990 'virtio11' => { bus
=> 2, addr
=> 6 },
4991 'virtio12' => { bus
=> 2, addr
=> 7 },
4992 'virtio13' => { bus
=> 2, addr
=> 8 },
4993 'virtio14' => { bus
=> 2, addr
=> 9 },
4994 'virtio15' => { bus
=> 2, addr
=> 10 },
4995 'virtioscsi0' => { bus
=> 3, addr
=> 1 },
4996 'virtioscsi1' => { bus
=> 3, addr
=> 2 },
4997 'virtioscsi2' => { bus
=> 3, addr
=> 3 },
4998 'virtioscsi3' => { bus
=> 3, addr
=> 4 },
4999 'virtioscsi4' => { bus
=> 3, addr
=> 5 },
5000 'virtioscsi5' => { bus
=> 3, addr
=> 6 },
5001 'virtioscsi6' => { bus
=> 3, addr
=> 7 },
5002 'virtioscsi7' => { bus
=> 3, addr
=> 8 },
5003 'virtioscsi8' => { bus
=> 3, addr
=> 9 },
5004 'virtioscsi9' => { bus
=> 3, addr
=> 10 },
5005 'virtioscsi10' => { bus
=> 3, addr
=> 11 },
5006 'virtioscsi11' => { bus
=> 3, addr
=> 12 },
5007 'virtioscsi12' => { bus
=> 3, addr
=> 13 },
5008 'virtioscsi13' => { bus
=> 3, addr
=> 14 },
5009 'virtioscsi14' => { bus
=> 3, addr
=> 15 },
5010 'virtioscsi15' => { bus
=> 3, addr
=> 16 },
5011 'virtioscsi16' => { bus
=> 3, addr
=> 17 },
5012 'virtioscsi17' => { bus
=> 3, addr
=> 18 },
5013 'virtioscsi18' => { bus
=> 3, addr
=> 19 },
5014 'virtioscsi19' => { bus
=> 3, addr
=> 20 },
5015 'virtioscsi20' => { bus
=> 3, addr
=> 21 },
5016 'virtioscsi21' => { bus
=> 3, addr
=> 22 },
5017 'virtioscsi22' => { bus
=> 3, addr
=> 23 },
5018 'virtioscsi23' => { bus
=> 3, addr
=> 24 },
5019 'virtioscsi24' => { bus
=> 3, addr
=> 25 },
5020 'virtioscsi25' => { bus
=> 3, addr
=> 26 },
5021 'virtioscsi26' => { bus
=> 3, addr
=> 27 },
5022 'virtioscsi27' => { bus
=> 3, addr
=> 28 },
5023 'virtioscsi28' => { bus
=> 3, addr
=> 29 },
5024 'virtioscsi29' => { bus
=> 3, addr
=> 30 },
5025 'virtioscsi30' => { bus
=> 3, addr
=> 31 },
5029 if (defined($devices->{$id}->{bus
}) && defined($devices->{$id}->{addr
})) {
5030 my $addr = sprintf("0x%x", $devices->{$id}->{addr
});
5031 my $bus = $devices->{$id}->{bus
};
5032 $res = ",bus=pci.$bus,addr=$addr";
5033 $bridges->{$bus} = 1 if $bridges;
5039 sub print_pcie_addr
{
5044 hostpci0
=> { bus
=> "ich9-pcie-port-1", addr
=> 0 },
5045 hostpci1
=> { bus
=> "ich9-pcie-port-2", addr
=> 0 },
5046 hostpci2
=> { bus
=> "ich9-pcie-port-3", addr
=> 0 },
5047 hostpci3
=> { bus
=> "ich9-pcie-port-4", addr
=> 0 },
5050 if (defined($devices->{$id}->{bus
}) && defined($devices->{$id}->{addr
})) {
5051 my $addr = sprintf("0x%x", $devices->{$id}->{addr
});
5052 my $bus = $devices->{$id}->{bus
};
5053 $res = ",bus=$bus,addr=$addr";
5059 # vzdump restore implementaion
5061 sub tar_archive_read_firstfile
{
5062 my $archive = shift;
5064 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5066 # try to detect archive type first
5067 my $pid = open (TMP
, "tar tf '$archive'|") ||
5068 die "unable to open file '$archive'\n";
5069 my $firstfile = <TMP
>;
5073 die "ERROR: archive contaions no data\n" if !$firstfile;
5079 sub tar_restore_cleanup
{
5080 my ($storecfg, $statfile) = @_;
5082 print STDERR
"starting cleanup\n";
5084 if (my $fd = IO
::File-
>new($statfile, "r")) {
5085 while (defined(my $line = <$fd>)) {
5086 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5089 if ($volid =~ m
|^/|) {
5090 unlink $volid || die 'unlink failed\n';
5092 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5094 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5096 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5098 print STDERR
"unable to parse line in statfile - $line";
5105 sub restore_archive
{
5106 my ($archive, $vmid, $user, $opts) = @_;
5108 my $format = $opts->{format
};
5111 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5112 $format = 'tar' if !$format;
5114 } elsif ($archive =~ m/\.tar$/) {
5115 $format = 'tar' if !$format;
5116 } elsif ($archive =~ m/.tar.lzo$/) {
5117 $format = 'tar' if !$format;
5119 } elsif ($archive =~ m/\.vma$/) {
5120 $format = 'vma' if !$format;
5121 } elsif ($archive =~ m/\.vma\.gz$/) {
5122 $format = 'vma' if !$format;
5124 } elsif ($archive =~ m/\.vma\.lzo$/) {
5125 $format = 'vma' if !$format;
5128 $format = 'vma' if !$format; # default
5131 # try to detect archive format
5132 if ($format eq 'tar') {
5133 return restore_tar_archive
($archive, $vmid, $user, $opts);
5135 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5139 sub restore_update_config_line
{
5140 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5142 return if $line =~ m/^\#qmdump\#/;
5143 return if $line =~ m/^\#vzdump\#/;
5144 return if $line =~ m/^lock:/;
5145 return if $line =~ m/^unused\d+:/;
5146 return if $line =~ m/^parent:/;
5147 return if $line =~ m/^template:/; # restored VM is never a template
5149 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5150 # try to convert old 1.X settings
5151 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5152 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5153 my ($model, $macaddr) = split(/\=/, $devconfig);
5154 $macaddr = PVE
::Tools
::random_ether_addr
() if !$macaddr || $unique;
5157 bridge
=> "vmbr$ind",
5158 macaddr
=> $macaddr,
5160 my $netstr = print_net
($net);
5162 print $outfd "net$cookie->{netcount}: $netstr\n";
5163 $cookie->{netcount
}++;
5165 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5166 my ($id, $netstr) = ($1, $2);
5167 my $net = parse_net
($netstr);
5168 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
() if $net->{macaddr
};
5169 $netstr = print_net
($net);
5170 print $outfd "$id: $netstr\n";
5171 } elsif ($line =~ m/^((ide|scsi|virtio|sata)\d+):\s*(\S+)\s*$/) {
5174 my $di = parse_drive
($virtdev, $value);
5175 if (defined($di->{backup
}) && !$di->{backup
}) {
5176 print $outfd "#$line";
5177 } elsif ($map->{$virtdev}) {
5178 delete $di->{format
}; # format can change on restore
5179 $di->{file
} = $map->{$virtdev};
5180 $value = print_drive
($vmid, $di);
5181 print $outfd "$virtdev: $value\n";
5191 my ($cfg, $vmid) = @_;
5193 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5195 my $volid_hash = {};
5196 foreach my $storeid (keys %$info) {
5197 foreach my $item (@{$info->{$storeid}}) {
5198 next if !($item->{volid
} && $item->{size
});
5199 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5200 $volid_hash->{$item->{volid
}} = $item;
5207 sub is_volume_in_use
{
5208 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5210 my $path = PVE
::Storage
::path
($storecfg, $volid);
5212 my $scan_config = sub {
5213 my ($cref, $snapname) = @_;
5215 foreach my $key (keys %$cref) {
5216 my $value = $cref->{$key};
5217 if (is_valid_drivename
($key)) {
5218 next if $skip_drive && $key eq $skip_drive;
5219 my $drive = parse_drive
($key, $value);
5220 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5221 return 1 if $volid eq $drive->{file
};
5222 if ($drive->{file
} =~ m!^/!) {
5223 return 1 if $drive->{file
} eq $path;
5225 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5227 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5229 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5237 return 1 if &$scan_config($conf);
5241 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5242 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5248 sub update_disksize
{
5249 my ($vmid, $conf, $volid_hash) = @_;
5255 # Note: it is allowed to define multiple storages with same path (alias), so
5256 # we need to check both 'volid' and real 'path' (two different volid can point
5257 # to the same path).
5262 foreach my $opt (keys %$conf) {
5263 if (is_valid_drivename
($opt)) {
5264 my $drive = parse_drive
($opt, $conf->{$opt});
5265 my $volid = $drive->{file
};
5268 $used->{$volid} = 1;
5269 if ($volid_hash->{$volid} &&
5270 (my $path = $volid_hash->{$volid}->{path
})) {
5271 $usedpath->{$path} = 1;
5274 next if drive_is_cdrom
($drive);
5275 next if !$volid_hash->{$volid};
5277 $drive->{size
} = $volid_hash->{$volid}->{size
};
5278 my $new = print_drive
($vmid, $drive);
5279 if ($new ne $conf->{$opt}) {
5281 $conf->{$opt} = $new;
5286 # remove 'unusedX' entry if volume is used
5287 foreach my $opt (keys %$conf) {
5288 next if $opt !~ m/^unused\d+$/;
5289 my $volid = $conf->{$opt};
5290 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5291 if ($used->{$volid} || ($path && $usedpath->{$path})) {
5293 delete $conf->{$opt};
5297 foreach my $volid (sort keys %$volid_hash) {
5298 next if $volid =~ m/vm-$vmid-state-/;
5299 next if $used->{$volid};
5300 my $path = $volid_hash->{$volid}->{path
};
5301 next if !$path; # just to be sure
5302 next if $usedpath->{$path};
5304 PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5305 $usedpath->{$path} = 1; # avoid to add more than once (aliases)
5312 my ($vmid, $nolock) = @_;
5314 my $cfg = PVE
::Cluster
::cfs_read_file
("storage.cfg");
5316 my $volid_hash = scan_volids
($cfg, $vmid);
5318 my $updatefn = sub {
5321 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5323 PVE
::QemuConfig-
>check_lock($conf);
5326 foreach my $volid (keys %$volid_hash) {
5327 my $info = $volid_hash->{$volid};
5328 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5331 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5333 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes;
5336 if (defined($vmid)) {
5340 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5343 my $vmlist = config_list
();
5344 foreach my $vmid (keys %$vmlist) {
5348 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5354 sub restore_vma_archive
{
5355 my ($archive, $vmid, $user, $opts, $comp) = @_;
5357 my $input = $archive eq '-' ?
"<&STDIN" : undef;
5358 my $readfrom = $archive;
5363 my $qarchive = PVE
::Tools
::shellquote
($archive);
5364 if ($comp eq 'gzip') {
5365 $uncomp = "zcat $qarchive|";
5366 } elsif ($comp eq 'lzop') {
5367 $uncomp = "lzop -d -c $qarchive|";
5369 die "unknown compression method '$comp'\n";
5374 my $tmpdir = "/var/tmp/vzdumptmp$$";
5377 # disable interrupts (always do cleanups)
5378 local $SIG{INT
} = $SIG{TERM
} = $SIG{QUIT
} = $SIG{HUP
} = sub {
5379 warn "got interrupt - ignored\n";
5382 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
5383 POSIX
::mkfifo
($mapfifo, 0600);
5386 my $openfifo = sub {
5387 open($fifofh, '>', $mapfifo) || die $!;
5390 my $cmd = "${uncomp}vma extract -v -r $mapfifo $readfrom $tmpdir";
5397 my $rpcenv = PVE
::RPCEnvironment
::get
();
5399 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5400 my $tmpfn = "$conffile.$$.tmp";
5402 # Note: $oldconf is undef if VM does not exists
5403 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
5404 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
5406 my $print_devmap = sub {
5407 my $virtdev_hash = {};
5409 my $cfgfn = "$tmpdir/qemu-server.conf";
5411 # we can read the config - that is already extracted
5412 my $fh = IO
::File-
>new($cfgfn, "r") ||
5413 "unable to read qemu-server.conf - $!\n";
5415 my $fwcfgfn = "$tmpdir/qemu-server.fw";
5417 my $pve_firewall_dir = '/etc/pve/firewall';
5418 mkdir $pve_firewall_dir; # make sure the dir exists
5419 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
5422 while (defined(my $line = <$fh>)) {
5423 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
5424 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
5425 die "archive does not contain data for drive '$virtdev'\n"
5426 if !$devinfo->{$devname};
5427 if (defined($opts->{storage
})) {
5428 $storeid = $opts->{storage
} || 'local';
5429 } elsif (!$storeid) {
5432 $format = 'raw' if !$format;
5433 $devinfo->{$devname}->{devname
} = $devname;
5434 $devinfo->{$devname}->{virtdev
} = $virtdev;
5435 $devinfo->{$devname}->{format
} = $format;
5436 $devinfo->{$devname}->{storeid
} = $storeid;
5438 # check permission on storage
5439 my $pool = $opts->{pool
}; # todo: do we need that?
5440 if ($user ne 'root@pam') {
5441 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
5444 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
5448 foreach my $devname (keys %$devinfo) {
5449 die "found no device mapping information for device '$devname'\n"
5450 if !$devinfo->{$devname}->{virtdev
};
5453 my $cfg = cfs_read_file
('storage.cfg');
5455 # create empty/temp config
5457 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
5458 foreach_drive
($oldconf, sub {
5459 my ($ds, $drive) = @_;
5461 return if drive_is_cdrom
($drive);
5463 my $volid = $drive->{file
};
5465 return if !$volid || $volid =~ m
|^/|;
5467 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
5468 return if !$path || !$owner || ($owner != $vmid);
5470 # Note: only delete disk we want to restore
5471 # other volumes will become unused
5472 if ($virtdev_hash->{$ds}) {
5473 PVE
::Storage
::vdisk_free
($cfg, $volid);
5477 # delete vmstate files
5478 # since after the restore we have no snapshots anymore
5479 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
5480 my $snap = $oldconf->{snapshots
}->{$snapname};
5481 if ($snap->{vmstate
}) {
5482 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
5491 foreach my $virtdev (sort keys %$virtdev_hash) {
5492 my $d = $virtdev_hash->{$virtdev};
5493 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
5494 my $scfg = PVE
::Storage
::storage_config
($cfg, $d->{storeid
});
5496 # test if requested format is supported
5497 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $d->{storeid
});
5498 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
5499 $d->{format
} = $defFormat if !$supported;
5501 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $d->{storeid
}, $vmid,
5502 $d->{format
}, undef, $alloc_size);
5503 print STDERR
"new volume ID is '$volid'\n";
5504 $d->{volid
} = $volid;
5505 my $path = PVE
::Storage
::path
($cfg, $volid);
5507 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
5509 my $write_zeros = 1;
5510 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
5514 print $fifofh "${write_zeros}:$d->{devname}=$path\n";
5516 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
5517 $map->{$virtdev} = $volid;
5520 $fh->seek(0, 0) || die "seek failed - $!\n";
5522 my $outfd = new IO
::File
($tmpfn, "w") ||
5523 die "unable to write config for VM $vmid\n";
5525 my $cookie = { netcount
=> 0 };
5526 while (defined(my $line = <$fh>)) {
5527 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
5536 local $SIG{INT
} = $SIG{TERM
} = $SIG{QUIT
} = $SIG{HUP
} = $SIG{PIPE
} = sub {
5537 die "interrupted by signal\n";
5539 local $SIG{ALRM
} = sub { die "got timeout\n"; };
5541 $oldtimeout = alarm($timeout);
5548 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
5549 my ($dev_id, $size, $devname) = ($1, $2, $3);
5550 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
5551 } elsif ($line =~ m/^CTIME: /) {
5552 # we correctly received the vma config, so we can disable
5553 # the timeout now for disk allocation (set to 10 minutes, so
5554 # that we always timeout if something goes wrong)
5557 print $fifofh "done\n";
5558 my $tmp = $oldtimeout || 0;
5559 $oldtimeout = undef;
5565 print "restore vma archive: $cmd\n";
5566 run_command
($cmd, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
5570 alarm($oldtimeout) if $oldtimeout;
5573 foreach my $devname (keys %$devinfo) {
5574 my $volid = $devinfo->{$devname}->{volid
};
5575 push @$vollist, $volid if $volid;
5578 my $cfg = cfs_read_file
('storage.cfg');
5579 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
5587 foreach my $devname (keys %$devinfo) {
5588 my $volid = $devinfo->{$devname}->{volid
};
5591 if ($volid =~ m
|^/|) {
5592 unlink $volid || die 'unlink failed\n';
5594 PVE
::Storage
::vdisk_free
($cfg, $volid);
5596 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5598 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5605 rename($tmpfn, $conffile) ||
5606 die "unable to commit configuration file '$conffile'\n";
5608 PVE
::Cluster
::cfs_update
(); # make sure we read new file
5610 eval { rescan
($vmid, 1); };
5614 sub restore_tar_archive
{
5615 my ($archive, $vmid, $user, $opts) = @_;
5617 if ($archive ne '-') {
5618 my $firstfile = tar_archive_read_firstfile
($archive);
5619 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
5620 if $firstfile ne 'qemu-server.conf';
5623 my $storecfg = cfs_read_file
('storage.cfg');
5625 # destroy existing data - keep empty config
5626 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
5627 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
5629 my $tocmd = "/usr/lib/qemu-server/qmextract";
5631 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
5632 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
5633 $tocmd .= ' --prealloc' if $opts->{prealloc
};
5634 $tocmd .= ' --info' if $opts->{info
};
5636 # tar option "xf" does not autodetect compression when read from STDIN,
5637 # so we pipe to zcat
5638 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
5639 PVE
::Tools
::shellquote
("--to-command=$tocmd");
5641 my $tmpdir = "/var/tmp/vzdumptmp$$";
5644 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
5645 local $ENV{VZDUMP_VMID
} = $vmid;
5646 local $ENV{VZDUMP_USER
} = $user;
5648 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5649 my $tmpfn = "$conffile.$$.tmp";
5651 # disable interrupts (always do cleanups)
5652 local $SIG{INT
} = $SIG{TERM
} = $SIG{QUIT
} = $SIG{HUP
} = sub {
5653 print STDERR
"got interrupt - ignored\n";
5658 local $SIG{INT
} = $SIG{TERM
} = $SIG{QUIT
} = $SIG{HUP
} = $SIG{PIPE
} = sub {
5659 die "interrupted by signal\n";
5662 if ($archive eq '-') {
5663 print "extracting archive from STDIN\n";
5664 run_command
($cmd, input
=> "<&STDIN");
5666 print "extracting archive '$archive'\n";
5670 return if $opts->{info
};
5674 my $statfile = "$tmpdir/qmrestore.stat";
5675 if (my $fd = IO
::File-
>new($statfile, "r")) {
5676 while (defined (my $line = <$fd>)) {
5677 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5678 $map->{$1} = $2 if $1;
5680 print STDERR
"unable to parse line in statfile - $line\n";
5686 my $confsrc = "$tmpdir/qemu-server.conf";
5688 my $srcfd = new IO
::File
($confsrc, "r") ||
5689 die "unable to open file '$confsrc'\n";
5691 my $outfd = new IO
::File
($tmpfn, "w") ||
5692 die "unable to write config for VM $vmid\n";
5694 my $cookie = { netcount
=> 0 };
5695 while (defined (my $line = <$srcfd>)) {
5696 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
5708 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
5715 rename $tmpfn, $conffile ||
5716 die "unable to commit configuration file '$conffile'\n";
5718 PVE
::Cluster
::cfs_update
(); # make sure we read new file
5720 eval { rescan
($vmid, 1); };
5724 sub foreach_writable_storage
{
5725 my ($conf, $func) = @_;
5729 foreach my $ds (keys %$conf) {
5730 next if !is_valid_drivename
($ds);
5732 my $drive = parse_drive
($ds, $conf->{$ds});
5734 next if drive_is_cdrom
($drive);
5736 my $volid = $drive->{file
};
5738 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
5739 $sidhash->{$sid} = $sid if $sid;
5742 foreach my $sid (sort keys %$sidhash) {
5747 sub do_snapshots_with_qemu
{
5748 my ($storecfg, $volid) = @_;
5750 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
5752 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
5753 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
5757 if ($volid =~ m/\.(qcow2|qed)$/){
5764 sub qga_check_running
{
5767 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
5769 warn "Qemu Guest Agent are not running - $@";
5775 sub template_create
{
5776 my ($vmid, $conf, $disk) = @_;
5778 my $storecfg = PVE
::Storage
::config
();
5780 foreach_drive
($conf, sub {
5781 my ($ds, $drive) = @_;
5783 return if drive_is_cdrom
($drive);
5784 return if $disk && $ds ne $disk;
5786 my $volid = $drive->{file
};
5787 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
5789 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
5790 $drive->{file
} = $voliddst;
5791 $conf->{$ds} = print_drive
($vmid, $drive);
5792 PVE
::QemuConfig-
>write_config($vmid, $conf);
5796 sub qemu_img_convert
{
5797 my ($src_volid, $dst_volid, $size, $snapname) = @_;
5799 my $storecfg = PVE
::Storage
::config
();
5800 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
5801 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
5803 if ($src_storeid && $dst_storeid) {
5805 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
5807 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
5808 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
5810 my $src_format = qemu_img_format
($src_scfg, $src_volname);
5811 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
5813 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
5814 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
5817 push @$cmd, '/usr/bin/qemu-img', 'convert', '-t', 'writeback', '-p', '-n';
5818 push @$cmd, '-s', $snapname if($snapname && $src_format eq "qcow2");
5819 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path, $dst_path;
5823 if($line =~ m/\((\S+)\/100\
%\)/){
5825 my $transferred = int($size * $percent / 100);
5826 my $remaining = $size - $transferred;
5828 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
5833 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
5835 die "copy failed: $err" if $err;
5839 sub qemu_img_format
{
5840 my ($scfg, $volname) = @_;
5842 if ($scfg->{path
} && $volname =~ m/\.(raw|cow|qcow|qcow2|qed|vmdk|cloop)$/) {
5849 sub qemu_drive_mirror
{
5850 my ($vmid, $drive, $dst_volid, $vmiddst) = @_;
5852 my $storecfg = PVE
::Storage
::config
();
5853 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
5855 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
5857 my $format = qemu_img_format
($dst_scfg, $dst_volname);
5859 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
5861 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $dst_path };
5862 $opts->{format
} = $format if $format;
5864 print "drive mirror is starting (scanning bitmap) : this step can take some minutes/hours, depend of disk size and storage speed\n";
5867 vm_mon_cmd
($vmid, "drive-mirror", %$opts);
5869 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
5870 my $stat = @$stats[0];
5871 die "mirroring job seem to have die. Maybe do you have bad sectors?" if !$stat;
5872 die "error job is not mirroring" if $stat->{type
} ne "mirror";
5874 my $busy = $stat->{busy
};
5875 my $ready = $stat->{ready
};
5877 if (my $total = $stat->{len
}) {
5878 my $transferred = $stat->{offset
} || 0;
5879 my $remaining = $total - $transferred;
5880 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
5882 print "transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
5886 if ($stat->{ready
} eq 'true') {
5888 last if $vmiddst != $vmid;
5890 # try to switch the disk if source and destination are on the same guest
5891 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> "drive-$drive") };
5893 die $@ if $@ !~ m/cannot be completed/;
5902 my $cancel_job = sub {
5903 vm_mon_cmd
($vmid, "block-job-cancel", device
=> "drive-$drive");
5905 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
5906 my $stat = @$stats[0];
5913 eval { &$cancel_job(); };
5914 die "mirroring error: $err";
5917 if ($vmiddst != $vmid) {
5918 # if we clone a disk for a new target vm, we don't switch the disk
5919 &$cancel_job(); # so we call block-job-cancel
5924 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
5925 $newvmid, $storage, $format, $full, $newvollist) = @_;
5930 print "create linked clone of drive $drivename ($drive->{file})\n";
5931 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
5932 push @$newvollist, $newvolid;
5934 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
5935 $storeid = $storage if $storage;
5937 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
5939 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
5940 $format = qemu_img_format
($scfg, $volname);
5943 # test if requested format is supported - else use default
5944 my $supported = grep { $_ eq $format } @$validFormats;
5945 $format = $defFormat if !$supported;
5947 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
5949 print "create full clone of drive $drivename ($drive->{file})\n";
5950 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $format, undef, ($size/1024));
5951 push @$newvollist, $newvolid;
5953 PVE
::Storage
::activate_volumes
($storecfg, $newvollist);
5955 if (!$running || $snapname) {
5956 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname);
5958 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid);
5962 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
5965 $disk->{format
} = undef;
5966 $disk->{file
} = $newvolid;
5967 $disk->{size
} = $size;
5972 # this only works if VM is running
5973 sub get_current_qemu_machine
{
5976 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
5977 my $res = vm_qmp_command
($vmid, $cmd);
5979 my ($current, $default);
5980 foreach my $e (@$res) {
5981 $default = $e->{name
} if $e->{'is-default'};
5982 $current = $e->{name
} if $e->{'is-current'};
5985 # fallback to the default machine if current is not supported by qemu
5986 return $current || $default || 'pc';
5989 sub qemu_machine_feature_enabled
{
5990 my ($machine, $kvmver, $version_major, $version_minor) = @_;
5995 if ($machine && $machine =~ m/^(pc(-i440fx|-q35)?-(\d+)\.(\d+))/) {
5997 $current_major = $3;
5998 $current_minor = $4;
6000 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6002 $current_major = $1;
6003 $current_minor = $2;
6006 return 1 if $current_major >= $version_major && $current_minor >= $version_minor;
6011 sub qemu_machine_pxe
{
6012 my ($vmid, $conf, $machine) = @_;
6014 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6016 foreach my $opt (keys %$conf) {
6017 next if $opt !~ m/^net(\d+)$/;
6018 my $net = PVE
::QemuServer
::parse_net
($conf->{$opt});
6020 my $romfile = PVE
::QemuServer
::vm_mon_cmd_nocheck
($vmid, 'qom-get', path
=> $opt, property
=> 'romfile');
6021 return $machine.".pxe" if $romfile =~ m/pxe/;
6028 sub qemu_use_old_bios_files
{
6029 my ($machine_type) = @_;
6031 return if !$machine_type;
6033 my $use_old_bios_files = undef;
6035 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6037 $use_old_bios_files = 1;
6039 my $kvmver = kvm_user_version
();
6040 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6041 # load new efi bios files on migration. So this hack is required to allow
6042 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6043 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6044 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6047 return ($use_old_bios_files, $machine_type);
6054 dir_glob_foreach
("$pcisysfs/devices", '[a-f0-9]{4}:([a-f0-9]{2}:[a-f0-9]{2})\.([0-9])', sub {
6055 my (undef, $id, $function) = @_;
6056 my $res = { id
=> $id, function
=> $function};
6057 push @{$devices->{$id}}, $res;
6063 sub vm_iothreads_list
{
6066 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6069 foreach my $iothread (@$res) {
6070 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6077 my ($conf, $drive) = @_;
6081 if ($conf->{scsihw
} && ($conf->{scsihw
} =~ m/^lsi/)) {
6083 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6089 my $controller = int($drive->{index} / $maxdev);
6090 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6092 return ($maxdev, $controller, $controller_prefix);
6095 # bash completion helper
6097 sub complete_backup_archives
{
6098 my ($cmdname, $pname, $cvalue) = @_;
6100 my $cfg = PVE
::Storage
::config
();
6104 if ($cvalue =~ m/^([^:]+):/) {
6108 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
6111 foreach my $id (keys %$data) {
6112 foreach my $item (@{$data->{$id}}) {
6113 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
6114 push @$res, $item->{volid
} if defined($item->{volid
});
6121 my $complete_vmid_full = sub {
6124 my $idlist = vmstatus
();
6128 foreach my $id (keys %$idlist) {
6129 my $d = $idlist->{$id};
6130 if (defined($running)) {
6131 next if $d->{template
};
6132 next if $running && $d->{status
} ne 'running';
6133 next if !$running && $d->{status
} eq 'running';
6142 return &$complete_vmid_full();
6145 sub complete_vmid_stopped
{
6146 return &$complete_vmid_full(0);
6149 sub complete_vmid_running
{
6150 return &$complete_vmid_full(1);
6153 sub complete_storage
{
6155 my $cfg = PVE
::Storage
::config
();
6156 my $ids = $cfg->{ids
};
6159 foreach my $sid (keys %$ids) {
6160 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
6161 next if !$ids->{$sid}->{content
}->{images
};