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 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);
1298 sub print_drive_full
{
1299 my ($storecfg, $vmid, $drive) = @_;
1302 my $volid = $drive->{file
};
1305 if (drive_is_cdrom
($drive)) {
1306 $path = get_iso_path
($storecfg, $vmid, $volid);
1308 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
1310 $path = PVE
::Storage
::path
($storecfg, $volid);
1311 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
1312 $format = qemu_img_format
($scfg, $volname);
1320 foreach my $o (@qemu_drive_options) {
1321 next if $o eq 'bootindex';
1322 $opts .= ",$o=$drive->{$o}" if $drive->{$o};
1325 $opts .= ",format=$format" if $format && !$drive->{format
};
1327 foreach my $o (qw(bps bps_rd bps_wr)) {
1328 my $v = $drive->{"m$o"};
1329 $opts .= ",$o=" . int($v*1024*1024) if $v;
1332 my $cache_direct = 0;
1334 if (my $cache = $drive->{cache
}) {
1335 $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
1336 } elsif (!drive_is_cdrom
($drive)) {
1337 $opts .= ",cache=none";
1341 # aio native works only with O_DIRECT
1342 if (!$drive->{aio
}) {
1344 $opts .= ",aio=native";
1346 $opts .= ",aio=threads";
1350 if (!drive_is_cdrom
($drive)) {
1352 if (defined($drive->{detect_zeroes
}) && !$drive->{detect_zeroes
}) {
1353 $detectzeroes = 'off';
1354 } elsif ($drive->{discard
}) {
1355 $detectzeroes = $drive->{discard
} eq 'on' ?
'unmap' : 'on';
1357 # This used to be our default with discard not being specified:
1358 $detectzeroes = 'on';
1360 $opts .= ",detect-zeroes=$detectzeroes" if $detectzeroes;
1363 my $pathinfo = $path ?
"file=$path," : '';
1365 return "${pathinfo}if=none,id=drive-$drive->{interface}$drive->{index}$opts";
1368 sub print_netdevice_full
{
1369 my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files) = @_;
1371 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
1373 my $device = $net->{model
};
1374 if ($net->{model
} eq 'virtio') {
1375 $device = 'virtio-net-pci';
1378 my $pciaddr = print_pci_addr
("$netid", $bridges);
1379 my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
1380 if ($net->{queues
} && $net->{queues
} > 1 && $net->{model
} eq 'virtio'){
1381 #Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
1382 my $vectors = $net->{queues
} * 2 + 2;
1383 $tmpstr .= ",vectors=$vectors,mq=on";
1385 $tmpstr .= ",bootindex=$net->{bootindex}" if $net->{bootindex
} ;
1387 if ($use_old_bios_files) {
1389 if ($device eq 'virtio-net-pci') {
1390 $romfile = 'pxe-virtio.rom';
1391 } elsif ($device eq 'e1000') {
1392 $romfile = 'pxe-e1000.rom';
1393 } elsif ($device eq 'ne2k') {
1394 $romfile = 'pxe-ne2k_pci.rom';
1395 } elsif ($device eq 'pcnet') {
1396 $romfile = 'pxe-pcnet.rom';
1397 } elsif ($device eq 'rtl8139') {
1398 $romfile = 'pxe-rtl8139.rom';
1400 $tmpstr .= ",romfile=$romfile" if $romfile;
1406 sub print_netdev_full
{
1407 my ($vmid, $conf, $net, $netid, $hotplug) = @_;
1410 if ($netid =~ m/^net(\d+)$/) {
1414 die "got strange net id '$i'\n" if $i >= ${MAX_NETS
};
1416 my $ifname = "tap${vmid}i$i";
1418 # kvm uses TUNSETIFF ioctl, and that limits ifname length
1419 die "interface name '$ifname' is too long (max 15 character)\n"
1420 if length($ifname) >= 16;
1422 my $vhostparam = '';
1423 $vhostparam = ',vhost=on' if $kernel_has_vhost_net && $net->{model
} eq 'virtio';
1425 my $vmname = $conf->{name
} || "vm$vmid";
1428 my $script = $hotplug ?
"pve-bridge-hotplug" : "pve-bridge";
1430 if ($net->{bridge
}) {
1431 $netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
1433 $netdev = "type=user,id=$netid,hostname=$vmname";
1436 $netdev .= ",queues=$net->{queues}" if ($net->{queues
} && $net->{model
} eq 'virtio');
1441 sub drive_is_cdrom
{
1444 return $drive && $drive->{media
} && ($drive->{media
} eq 'cdrom');
1453 foreach my $kvp (split(/,/, $data)) {
1455 if ($kvp =~ m/^memory=(\S+)$/) {
1456 $res->{memory
} = $1;
1457 } elsif ($kvp =~ m/^policy=(preferred|bind|interleave)$/) {
1458 $res->{policy
} = $1;
1459 } elsif ($kvp =~ m/^cpus=(\d+)(-(\d+))?$/) {
1460 $res->{cpus
}->{start
} = $1;
1461 $res->{cpus
}->{end
} = $3;
1462 } elsif ($kvp =~ m/^hostnodes=(\d+)(-(\d+))?$/) {
1463 $res->{hostnodes
}->{start
} = $1;
1464 $res->{hostnodes
}->{end
} = $3;
1476 return undef if !$value;
1479 my @list = split(/,/, $value);
1483 foreach my $kv (@list) {
1485 if ($kv =~ m/^(host=)?([a-f0-9]{2}:[a-f0-9]{2})(\.([a-f0-9]))?$/) {
1488 push @{$res->{pciid
}}, { id
=> $2 , function
=> $4};
1491 my $pcidevices = lspci
($2);
1492 $res->{pciid
} = $pcidevices->{$2};
1494 } elsif ($kv =~ m/^rombar=(on|off)$/) {
1495 $res->{rombar
} = $1;
1496 } elsif ($kv =~ m/^x-vga=(on|off)$/) {
1497 $res->{'x-vga'} = $1;
1498 } elsif ($kv =~ m/^pcie=(\d+)$/) {
1499 $res->{pcie
} = 1 if $1 == 1;
1501 warn "unknown hostpci setting '$kv'\n";
1505 return undef if !$found;
1510 # netX: e1000=XX:XX:XX:XX:XX:XX,bridge=vmbr0,rate=<mbps>
1516 foreach my $kvp (split(/,/, $data)) {
1518 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) {
1520 my $mac = defined($3) ?
uc($3) : PVE
::Tools
::random_ether_addr
();
1521 $res->{model
} = $model;
1522 $res->{macaddr
} = $mac;
1523 } elsif ($kvp =~ m/^bridge=(\S+)$/) {
1524 $res->{bridge
} = $1;
1525 } elsif ($kvp =~ m/^queues=(\d+)$/) {
1526 $res->{queues
} = $1;
1527 } elsif ($kvp =~ m/^rate=(\d+(\.\d+)?)$/) {
1529 } elsif ($kvp =~ m/^tag=(\d+)$/) {
1531 } elsif ($kvp =~ m/^trunks=([0-9;]+)$/) {
1532 $res->{trunks
} = $1;
1533 } elsif ($kvp =~ m/^firewall=([01])$/) {
1534 $res->{firewall
} = $1;
1535 } elsif ($kvp =~ m/^link_down=([01])$/) {
1536 $res->{link_down
} = $1;
1543 return undef if !$res->{model
};
1551 my $res = "$net->{model}";
1552 $res .= "=$net->{macaddr}" if $net->{macaddr
};
1553 $res .= ",bridge=$net->{bridge}" if $net->{bridge
};
1554 $res .= ",rate=$net->{rate}" if $net->{rate
};
1555 $res .= ",tag=$net->{tag}" if $net->{tag
};
1556 $res .= ",trunks=$net->{trunks}" if $net->{trunks
};
1557 $res .= ",firewall=1" if $net->{firewall
};
1558 $res .= ",link_down=1" if $net->{link_down
};
1559 $res .= ",queues=$net->{queues}" if $net->{queues
};
1564 sub add_random_macs
{
1565 my ($settings) = @_;
1567 foreach my $opt (keys %$settings) {
1568 next if $opt !~ m/^net(\d+)$/;
1569 my $net = parse_net
($settings->{$opt});
1571 $settings->{$opt} = print_net
($net);
1575 sub vm_is_volid_owner
{
1576 my ($storecfg, $vmid, $volid) = @_;
1578 if ($volid !~ m
|^/|) {
1580 eval { ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid); };
1581 if ($owner && ($owner == $vmid)) {
1589 sub split_flagged_list
{
1590 my $text = shift || '';
1591 $text =~ s/[,;]/ /g;
1593 return { map { /^(!?)(.*)$/ && ($2, $1) } ($text =~ /\S+/g) };
1596 sub join_flagged_list
{
1597 my ($how, $lst) = @_;
1598 join $how, map { $lst->{$_} . $_ } keys %$lst;
1601 sub vmconfig_delete_pending_option
{
1602 my ($conf, $key, $force) = @_;
1604 delete $conf->{pending
}->{$key};
1605 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
1606 $pending_delete_hash->{$key} = $force ?
'!' : '';
1607 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
1610 sub vmconfig_undelete_pending_option
{
1611 my ($conf, $key) = @_;
1613 my $pending_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
1614 delete $pending_delete_hash->{$key};
1616 if (%$pending_delete_hash) {
1617 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
1619 delete $conf->{pending
}->{delete};
1623 sub vmconfig_register_unused_drive
{
1624 my ($storecfg, $vmid, $conf, $drive) = @_;
1626 if (!drive_is_cdrom
($drive)) {
1627 my $volid = $drive->{file
};
1628 if (vm_is_volid_owner
($storecfg, $vmid, $volid)) {
1629 PVE
::QemuConfig-
>add_unused_volume($conf, $volid, $vmid);
1634 sub vmconfig_cleanup_pending
{
1637 # remove pending changes when nothing changed
1639 foreach my $opt (keys %{$conf->{pending
}}) {
1640 if (defined($conf->{$opt}) && ($conf->{pending
}->{$opt} eq $conf->{$opt})) {
1642 delete $conf->{pending
}->{$opt};
1646 my $current_delete_hash = split_flagged_list
($conf->{pending
}->{delete});
1647 my $pending_delete_hash = {};
1648 while (my ($opt, $force) = each %$current_delete_hash) {
1649 if (defined($conf->{$opt})) {
1650 $pending_delete_hash->{$opt} = $force;
1656 if (%$pending_delete_hash) {
1657 $conf->{pending
}->{delete} = join_flagged_list
(',', $pending_delete_hash);
1659 delete $conf->{pending
}->{delete};
1665 # smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
1666 my $smbios1_desc = {
1669 pattern
=> '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
1670 format_description
=> 'UUID',
1676 format_description
=> 'str',
1682 format_description
=> 'str',
1688 format_description
=> 'name',
1694 format_description
=> 'name',
1700 format_description
=> 'str',
1706 format_description
=> 'str',
1714 my $res = eval { PVE
::JSONSchema
::parse_property_string
($smbios1_desc, $data) };
1721 return PVE
::JSONSchema
::print_property_string
($smbios1, $smbios1_desc);
1724 PVE
::JSONSchema
::register_format
('pve-qm-smbios1', $smbios1_desc);
1726 PVE
::JSONSchema
::register_format
('pve-qm-bootdisk', \
&verify_bootdisk
);
1727 sub verify_bootdisk
{
1728 my ($value, $noerr) = @_;
1730 return $value if is_valid_drivename
($value);
1732 return undef if $noerr;
1734 die "invalid boot disk '$value'\n";
1737 PVE
::JSONSchema
::register_format
('pve-qm-numanode', \
&verify_numa
);
1739 my ($value, $noerr) = @_;
1741 return $value if parse_numa
($value);
1743 return undef if $noerr;
1745 die "unable to parse numa options\n";
1748 PVE
::JSONSchema
::register_format
('pve-qm-net', \
&verify_net
);
1750 my ($value, $noerr) = @_;
1752 return $value if parse_net
($value);
1754 return undef if $noerr;
1756 die "unable to parse network options\n";
1759 PVE
::JSONSchema
::register_format
('pve-qm-hostpci', \
&verify_hostpci
);
1760 sub verify_hostpci
{
1761 my ($value, $noerr) = @_;
1763 return $value if parse_hostpci
($value);
1765 return undef if $noerr;
1767 die "unable to parse pci id\n";
1770 PVE
::JSONSchema
::register_format
('pve-qm-watchdog', \
&verify_watchdog
);
1771 sub verify_watchdog
{
1772 my ($value, $noerr) = @_;
1774 return $value if parse_watchdog
($value);
1776 return undef if $noerr;
1778 die "unable to parse watchdog options\n";
1781 sub parse_watchdog
{
1784 return undef if !$value;
1788 foreach my $p (split(/,/, $value)) {
1789 next if $p =~ m/^\s*$/;
1791 if ($p =~ m/^(model=)?(i6300esb|ib700)$/) {
1793 } elsif ($p =~ m/^(action=)?(reset|shutdown|poweroff|pause|debug|none)$/) {
1794 $res->{action
} = $2;
1803 sub parse_usb_device
{
1806 return undef if !$value;
1809 if ($value =~ m/^(0x)?([0-9A-Fa-f]{4}):(0x)?([0-9A-Fa-f]{4})$/) {
1810 $res->{vendorid
} = $2;
1811 $res->{productid
} = $4;
1812 } elsif ($value =~ m/^(\d+)\-(\d+(\.\d+)*)$/) {
1813 $res->{hostbus
} = $1;
1814 $res->{hostport
} = $2;
1815 } elsif ($value =~ m/^spice$/i) {
1824 PVE
::JSONSchema
::register_format
('pve-qm-usb-device', \
&verify_usb_device
);
1825 sub verify_usb_device
{
1826 my ($value, $noerr) = @_;
1828 return $value if parse_usb_device
($value);
1830 return undef if $noerr;
1832 die "unable to parse usb device\n";
1835 # add JSON properties for create and set function
1836 sub json_config_properties
{
1839 foreach my $opt (keys %$confdesc) {
1840 next if $opt eq 'parent' || $opt eq 'snaptime' || $opt eq 'vmstate';
1841 $prop->{$opt} = $confdesc->{$opt};
1848 my ($key, $value) = @_;
1850 die "unknown setting '$key'\n" if !$confdesc->{$key};
1852 my $type = $confdesc->{$key}->{type
};
1854 if (!defined($value)) {
1855 die "got undefined value\n";
1858 if ($value =~ m/[\n\r]/) {
1859 die "property contains a line feed\n";
1862 if ($type eq 'boolean') {
1863 return 1 if ($value eq '1') || ($value =~ m/^(on|yes|true)$/i);
1864 return 0 if ($value eq '0') || ($value =~ m/^(off|no|false)$/i);
1865 die "type check ('boolean') failed - got '$value'\n";
1866 } elsif ($type eq 'integer') {
1867 return int($1) if $value =~ m/^(\d+)$/;
1868 die "type check ('integer') failed - got '$value'\n";
1869 } elsif ($type eq 'number') {
1870 return $value if $value =~ m/^(\d+)(\.\d+)?$/;
1871 die "type check ('number') failed - got '$value'\n";
1872 } elsif ($type eq 'string') {
1873 if (my $fmt = $confdesc->{$key}->{format
}) {
1874 if ($fmt eq 'pve-qm-drive') {
1875 # special case - we need to pass $key to parse_drive()
1876 my $drive = parse_drive
($key, $value);
1877 return $value if $drive;
1878 die "unable to parse drive options\n";
1880 PVE
::JSONSchema
::check_format
($fmt, $value);
1883 $value =~ s/^\"(.*)\"$/$1/;
1886 die "internal error"
1890 sub check_iommu_support
{
1891 #fixme : need to check IOMMU support
1892 #http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM
1902 my $conf = PVE
::QemuConfig-
>config_file($vmid);
1903 utime undef, undef, $conf;
1907 my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
1909 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
1911 my $conf = PVE
::QemuConfig-
>load_config($vmid);
1913 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
1915 # only remove disks owned by this VM
1916 foreach_drive
($conf, sub {
1917 my ($ds, $drive) = @_;
1919 return if drive_is_cdrom
($drive);
1921 my $volid = $drive->{file
};
1923 return if !$volid || $volid =~ m
|^/|;
1925 my ($path, $owner) = PVE
::Storage
::path
($storecfg, $volid);
1926 return if !$path || !$owner || ($owner != $vmid);
1928 PVE
::Storage
::vdisk_free
($storecfg, $volid);
1931 if ($keep_empty_config) {
1932 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
1937 # also remove unused disk
1939 my $dl = PVE
::Storage
::vdisk_list
($storecfg, undef, $vmid);
1942 PVE
::Storage
::foreach_volid
($dl, sub {
1943 my ($volid, $sid, $volname, $d) = @_;
1944 PVE
::Storage
::vdisk_free
($storecfg, $volid);
1953 sub parse_vm_config
{
1954 my ($filename, $raw) = @_;
1956 return undef if !defined($raw);
1959 digest
=> Digest
::SHA
::sha1_hex
($raw),
1964 $filename =~ m
|/qemu-server/(\d
+)\
.conf
$|
1965 || die "got strange filename '$filename'";
1973 my @lines = split(/\n/, $raw);
1974 foreach my $line (@lines) {
1975 next if $line =~ m/^\s*$/;
1977 if ($line =~ m/^\[PENDING\]\s*$/i) {
1978 $section = 'pending';
1979 if (defined($descr)) {
1981 $conf->{description
} = $descr;
1984 $conf = $res->{$section} = {};
1987 } elsif ($line =~ m/^\[([a-z][a-z0-9_\-]+)\]\s*$/i) {
1989 if (defined($descr)) {
1991 $conf->{description
} = $descr;
1994 $conf = $res->{snapshots
}->{$section} = {};
1998 if ($line =~ m/^\#(.*)\s*$/) {
1999 $descr = '' if !defined($descr);
2000 $descr .= PVE
::Tools
::decode_text
($1) . "\n";
2004 if ($line =~ m/^(description):\s*(.*\S)\s*$/) {
2005 $descr = '' if !defined($descr);
2006 $descr .= PVE
::Tools
::decode_text
($2);
2007 } elsif ($line =~ m/snapstate:\s*(prepare|delete)\s*$/) {
2008 $conf->{snapstate
} = $1;
2009 } elsif ($line =~ m/^(args):\s*(.*\S)\s*$/) {
2012 $conf->{$key} = $value;
2013 } elsif ($line =~ m/^delete:\s*(.*\S)\s*$/) {
2015 if ($section eq 'pending') {
2016 $conf->{delete} = $value; # we parse this later
2018 warn "vm $vmid - propertry 'delete' is only allowed in [PENDING]\n";
2020 } elsif ($line =~ m/^([a-z][a-z_]*\d*):\s*(\S+)\s*$/) {
2023 eval { $value = check_type
($key, $value); };
2025 warn "vm $vmid - unable to parse value of '$key' - $@";
2027 my $fmt = $confdesc->{$key}->{format
};
2028 if ($fmt && $fmt eq 'pve-qm-drive') {
2029 my $v = parse_drive
($key, $value);
2030 if (my $volid = filename_to_volume_id
($vmid, $v->{file
}, $v->{media
})) {
2031 $v->{file
} = $volid;
2032 $value = print_drive
($vmid, $v);
2034 warn "vm $vmid - unable to parse value of '$key'\n";
2039 if ($key eq 'cdrom') {
2040 $conf->{ide2
} = $value;
2042 $conf->{$key} = $value;
2048 if (defined($descr)) {
2050 $conf->{description
} = $descr;
2052 delete $res->{snapstate
}; # just to be sure
2057 sub write_vm_config
{
2058 my ($filename, $conf) = @_;
2060 delete $conf->{snapstate
}; # just to be sure
2062 if ($conf->{cdrom
}) {
2063 die "option ide2 conflicts with cdrom\n" if $conf->{ide2
};
2064 $conf->{ide2
} = $conf->{cdrom
};
2065 delete $conf->{cdrom
};
2068 # we do not use 'smp' any longer
2069 if ($conf->{sockets
}) {
2070 delete $conf->{smp
};
2071 } elsif ($conf->{smp
}) {
2072 $conf->{sockets
} = $conf->{smp
};
2073 delete $conf->{cores
};
2074 delete $conf->{smp
};
2077 my $used_volids = {};
2079 my $cleanup_config = sub {
2080 my ($cref, $pending, $snapname) = @_;
2082 foreach my $key (keys %$cref) {
2083 next if $key eq 'digest' || $key eq 'description' || $key eq 'snapshots' ||
2084 $key eq 'snapstate' || $key eq 'pending';
2085 my $value = $cref->{$key};
2086 if ($key eq 'delete') {
2087 die "propertry 'delete' is only allowed in [PENDING]\n"
2089 # fixme: check syntax?
2092 eval { $value = check_type
($key, $value); };
2093 die "unable to parse value of '$key' - $@" if $@;
2095 $cref->{$key} = $value;
2097 if (!$snapname && is_valid_drivename
($key)) {
2098 my $drive = parse_drive
($key, $value);
2099 $used_volids->{$drive->{file
}} = 1 if $drive && $drive->{file
};
2104 &$cleanup_config($conf);
2106 &$cleanup_config($conf->{pending
}, 1);
2108 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2109 die "internal error" if $snapname eq 'pending';
2110 &$cleanup_config($conf->{snapshots
}->{$snapname}, undef, $snapname);
2113 # remove 'unusedX' settings if we re-add a volume
2114 foreach my $key (keys %$conf) {
2115 my $value = $conf->{$key};
2116 if ($key =~ m/^unused/ && $used_volids->{$value}) {
2117 delete $conf->{$key};
2121 my $generate_raw_config = sub {
2122 my ($conf, $pending) = @_;
2126 # add description as comment to top of file
2127 if (defined(my $descr = $conf->{description
})) {
2129 foreach my $cl (split(/\n/, $descr)) {
2130 $raw .= '#' . PVE
::Tools
::encode_text
($cl) . "\n";
2133 $raw .= "#\n" if $pending;
2137 foreach my $key (sort keys %$conf) {
2138 next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
2139 $raw .= "$key: $conf->{$key}\n";
2144 my $raw = &$generate_raw_config($conf);
2146 if (scalar(keys %{$conf->{pending
}})){
2147 $raw .= "\n[PENDING]\n";
2148 $raw .= &$generate_raw_config($conf->{pending
}, 1);
2151 foreach my $snapname (sort keys %{$conf->{snapshots
}}) {
2152 $raw .= "\n[$snapname]\n";
2153 $raw .= &$generate_raw_config($conf->{snapshots
}->{$snapname});
2163 # we use static defaults from our JSON schema configuration
2164 foreach my $key (keys %$confdesc) {
2165 if (defined(my $default = $confdesc->{$key}->{default})) {
2166 $res->{$key} = $default;
2170 my $conf = PVE
::Cluster
::cfs_read_file
('datacenter.cfg');
2171 $res->{keyboard
} = $conf->{keyboard
} if $conf->{keyboard
};
2177 my $vmlist = PVE
::Cluster
::get_vmlist
();
2179 return $res if !$vmlist || !$vmlist->{ids
};
2180 my $ids = $vmlist->{ids
};
2182 foreach my $vmid (keys %$ids) {
2183 my $d = $ids->{$vmid};
2184 next if !$d->{node
} || $d->{node
} ne $nodename;
2185 next if !$d->{type
} || $d->{type
} ne 'qemu';
2186 $res->{$vmid}->{exists} = 1;
2191 # test if VM uses local resources (to prevent migration)
2192 sub check_local_resources
{
2193 my ($conf, $noerr) = @_;
2197 $loc_res = 1 if $conf->{hostusb
}; # old syntax
2198 $loc_res = 1 if $conf->{hostpci
}; # old syntax
2200 foreach my $k (keys %$conf) {
2201 next if $k =~ m/^usb/ && ($conf->{$k} eq 'spice');
2202 # sockets are safe: they will recreated be on the target side post-migrate
2203 next if $k =~ m/^serial/ && ($conf->{$k} eq 'socket');
2204 $loc_res = 1 if $k =~ m/^(usb|hostpci|serial|parallel)\d+$/;
2207 die "VM uses local resources\n" if $loc_res && !$noerr;
2212 # check if used storages are available on all nodes (use by migrate)
2213 sub check_storage_availability
{
2214 my ($storecfg, $conf, $node) = @_;
2216 foreach_drive
($conf, sub {
2217 my ($ds, $drive) = @_;
2219 my $volid = $drive->{file
};
2222 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2225 # check if storage is available on both nodes
2226 my $scfg = PVE
::Storage
::storage_check_node
($storecfg, $sid);
2227 PVE
::Storage
::storage_check_node
($storecfg, $sid, $node);
2231 # list nodes where all VM images are available (used by has_feature API)
2233 my ($conf, $storecfg) = @_;
2235 my $nodelist = PVE
::Cluster
::get_nodelist
();
2236 my $nodehash = { map { $_ => 1 } @$nodelist };
2237 my $nodename = PVE
::INotify
::nodename
();
2239 foreach_drive
($conf, sub {
2240 my ($ds, $drive) = @_;
2242 my $volid = $drive->{file
};
2245 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
2247 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
2248 if ($scfg->{disable
}) {
2250 } elsif (my $avail = $scfg->{nodes
}) {
2251 foreach my $node (keys %$nodehash) {
2252 delete $nodehash->{$node} if !$avail->{$node};
2254 } elsif (!$scfg->{shared
}) {
2255 foreach my $node (keys %$nodehash) {
2256 delete $nodehash->{$node} if $node ne $nodename
2266 my ($pidfile, $pid) = @_;
2268 my $fh = IO
::File-
>new("/proc/$pid/cmdline", "r");
2272 return undef if !$line;
2273 my @param = split(/\0/, $line);
2275 my $cmd = $param[0];
2276 return if !$cmd || ($cmd !~ m
|kvm
$| && $cmd !~ m
|qemu-system-x86_64
$|);
2278 for (my $i = 0; $i < scalar (@param); $i++) {
2281 if (($p eq '-pidfile') || ($p eq '--pidfile')) {
2282 my $p = $param[$i+1];
2283 return 1 if $p && ($p eq $pidfile);
2292 my ($vmid, $nocheck, $node) = @_;
2294 my $filename = PVE
::QemuConfig-
>config_file($vmid, $node);
2296 die "unable to find configuration file for VM $vmid - no such machine\n"
2297 if !$nocheck && ! -f
$filename;
2299 my $pidfile = pidfile_name
($vmid);
2301 if (my $fd = IO
::File-
>new("<$pidfile")) {
2306 my $mtime = $st->mtime;
2307 if ($mtime > time()) {
2308 warn "file '$filename' modified in future\n";
2311 if ($line =~ m/^(\d+)$/) {
2313 if (check_cmdline
($pidfile, $pid)) {
2314 if (my $pinfo = PVE
::ProcFSTools
::check_process_running
($pid)) {
2326 my $vzlist = config_list
();
2328 my $fd = IO
::Dir-
>new($var_run_tmpdir) || return $vzlist;
2330 while (defined(my $de = $fd->read)) {
2331 next if $de !~ m/^(\d+)\.pid$/;
2333 next if !defined($vzlist->{$vmid});
2334 if (my $pid = check_running
($vmid)) {
2335 $vzlist->{$vmid}->{pid
} = $pid;
2343 my ($storecfg, $conf) = @_;
2345 my $bootdisk = $conf->{bootdisk
};
2346 return undef if !$bootdisk;
2347 return undef if !is_valid_drivename
($bootdisk);
2349 return undef if !$conf->{$bootdisk};
2351 my $drive = parse_drive
($bootdisk, $conf->{$bootdisk});
2352 return undef if !defined($drive);
2354 return undef if drive_is_cdrom
($drive);
2356 my $volid = $drive->{file
};
2357 return undef if !$volid;
2359 return $drive->{size
};
2362 my $last_proc_pid_stat;
2364 # get VM status information
2365 # This must be fast and should not block ($full == false)
2366 # We only query KVM using QMP if $full == true (this can be slow)
2368 my ($opt_vmid, $full) = @_;
2372 my $storecfg = PVE
::Storage
::config
();
2374 my $list = vzlist
();
2375 my ($uptime) = PVE
::ProcFSTools
::read_proc_uptime
(1);
2377 my $cpucount = $cpuinfo->{cpus
} || 1;
2379 foreach my $vmid (keys %$list) {
2380 next if $opt_vmid && ($vmid ne $opt_vmid);
2382 my $cfspath = PVE
::QemuConfig-
>cfs_config_path($vmid);
2383 my $conf = PVE
::Cluster
::cfs_read_file
($cfspath) || {};
2386 $d->{pid
} = $list->{$vmid}->{pid
};
2388 # fixme: better status?
2389 $d->{status
} = $list->{$vmid}->{pid
} ?
'running' : 'stopped';
2391 my $size = disksize
($storecfg, $conf);
2392 if (defined($size)) {
2393 $d->{disk
} = 0; # no info available
2394 $d->{maxdisk
} = $size;
2400 $d->{cpus
} = ($conf->{sockets
} || 1) * ($conf->{cores
} || 1);
2401 $d->{cpus
} = $cpucount if $d->{cpus
} > $cpucount;
2402 $d->{cpus
} = $conf->{vcpus
} if $conf->{vcpus
};
2404 $d->{name
} = $conf->{name
} || "VM $vmid";
2405 $d->{maxmem
} = $conf->{memory
} ?
$conf->{memory
}*(1024*1024) : 0;
2407 if ($conf->{balloon
}) {
2408 $d->{balloon_min
} = $conf->{balloon
}*(1024*1024);
2409 $d->{shares
} = defined($conf->{shares
}) ?
$conf->{shares
} : 1000;
2420 $d->{diskwrite
} = 0;
2422 $d->{template
} = PVE
::QemuConfig-
>is_template($conf);
2427 my $netdev = PVE
::ProcFSTools
::read_proc_net_dev
();
2428 foreach my $dev (keys %$netdev) {
2429 next if $dev !~ m/^tap([1-9]\d*)i/;
2431 my $d = $res->{$vmid};
2434 $d->{netout
} += $netdev->{$dev}->{receive
};
2435 $d->{netin
} += $netdev->{$dev}->{transmit
};
2438 $d->{nics
}->{$dev}->{netout
} = $netdev->{$dev}->{receive
};
2439 $d->{nics
}->{$dev}->{netin
} = $netdev->{$dev}->{transmit
};
2444 my $ctime = gettimeofday
;
2446 foreach my $vmid (keys %$list) {
2448 my $d = $res->{$vmid};
2449 my $pid = $d->{pid
};
2452 my $pstat = PVE
::ProcFSTools
::read_proc_pid_stat
($pid);
2453 next if !$pstat; # not running
2455 my $used = $pstat->{utime} + $pstat->{stime
};
2457 $d->{uptime
} = int(($uptime - $pstat->{starttime
})/$cpuinfo->{user_hz
});
2459 if ($pstat->{vsize
}) {
2460 $d->{mem
} = int(($pstat->{rss
}/$pstat->{vsize
})*$d->{maxmem
});
2463 my $old = $last_proc_pid_stat->{$pid};
2465 $last_proc_pid_stat->{$pid} = {
2473 my $dtime = ($ctime - $old->{time}) * $cpucount * $cpuinfo->{user_hz
};
2475 if ($dtime > 1000) {
2476 my $dutime = $used - $old->{used
};
2478 $d->{cpu
} = (($dutime/$dtime)* $cpucount) / $d->{cpus
};
2479 $last_proc_pid_stat->{$pid} = {
2485 $d->{cpu
} = $old->{cpu
};
2489 return $res if !$full;
2491 my $qmpclient = PVE
::QMPClient-
>new();
2493 my $ballooncb = sub {
2494 my ($vmid, $resp) = @_;
2496 my $info = $resp->{'return'};
2497 return if !$info->{max_mem
};
2499 my $d = $res->{$vmid};
2501 # use memory assigned to VM
2502 $d->{maxmem
} = $info->{max_mem
};
2503 $d->{balloon
} = $info->{actual
};
2505 if (defined($info->{total_mem
}) && defined($info->{free_mem
})) {
2506 $d->{mem
} = $info->{total_mem
} - $info->{free_mem
};
2507 $d->{freemem
} = $info->{free_mem
};
2510 $d->{ballooninfo
} = $info;
2513 my $blockstatscb = sub {
2514 my ($vmid, $resp) = @_;
2515 my $data = $resp->{'return'} || [];
2516 my $totalrdbytes = 0;
2517 my $totalwrbytes = 0;
2519 for my $blockstat (@$data) {
2520 $totalrdbytes = $totalrdbytes + $blockstat->{stats
}->{rd_bytes
};
2521 $totalwrbytes = $totalwrbytes + $blockstat->{stats
}->{wr_bytes
};
2523 $blockstat->{device
} =~ s/drive-//;
2524 $res->{$vmid}->{blockstat
}->{$blockstat->{device
}} = $blockstat->{stats
};
2526 $res->{$vmid}->{diskread
} = $totalrdbytes;
2527 $res->{$vmid}->{diskwrite
} = $totalwrbytes;
2530 my $statuscb = sub {
2531 my ($vmid, $resp) = @_;
2533 $qmpclient->queue_cmd($vmid, $blockstatscb, 'query-blockstats');
2534 # this fails if ballon driver is not loaded, so this must be
2535 # the last commnand (following command are aborted if this fails).
2536 $qmpclient->queue_cmd($vmid, $ballooncb, 'query-balloon');
2538 my $status = 'unknown';
2539 if (!defined($status = $resp->{'return'}->{status
})) {
2540 warn "unable to get VM status\n";
2544 $res->{$vmid}->{qmpstatus
} = $resp->{'return'}->{status
};
2547 foreach my $vmid (keys %$list) {
2548 next if $opt_vmid && ($vmid ne $opt_vmid);
2549 next if !$res->{$vmid}->{pid
}; # not running
2550 $qmpclient->queue_cmd($vmid, $statuscb, 'query-status');
2553 $qmpclient->queue_execute(undef, 1);
2555 foreach my $vmid (keys %$list) {
2556 next if $opt_vmid && ($vmid ne $opt_vmid);
2557 $res->{$vmid}->{qmpstatus
} = $res->{$vmid}->{status
} if !$res->{$vmid}->{qmpstatus
};
2564 my ($conf, $vmid, $memory, $sockets, $func) = @_;
2567 my $current_size = 1024;
2568 my $dimm_size = 512;
2569 return if $current_size == $memory;
2571 for (my $j = 0; $j < 8; $j++) {
2572 for (my $i = 0; $i < 32; $i++) {
2573 my $name = "dimm${dimm_id}";
2575 my $numanode = $i % $sockets;
2576 $current_size += $dimm_size;
2577 &$func($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory);
2578 return $current_size if $current_size >= $memory;
2584 sub foreach_reverse_dimm
{
2585 my ($conf, $vmid, $memory, $sockets, $func) = @_;
2588 my $current_size = 4177920;
2589 my $dimm_size = 65536;
2590 return if $current_size == $memory;
2592 for (my $j = 0; $j < 8; $j++) {
2593 for (my $i = 0; $i < 32; $i++) {
2594 my $name = "dimm${dimm_id}";
2596 my $numanode = $i % $sockets;
2597 $current_size -= $dimm_size;
2598 &$func($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory);
2599 return $current_size if $current_size <= $memory;
2606 my ($conf, $func) = @_;
2608 foreach my $ds (valid_drive_names
()) {
2609 next if !defined($conf->{$ds});
2611 my $drive = parse_drive
($ds, $conf->{$ds});
2614 &$func($ds, $drive);
2619 my ($conf, $func) = @_;
2623 my $test_volid = sub {
2624 my ($volid, $is_cdrom) = @_;
2628 $volhash->{$volid} = $is_cdrom || 0;
2631 foreach_drive
($conf, sub {
2632 my ($ds, $drive) = @_;
2633 &$test_volid($drive->{file
}, drive_is_cdrom
($drive));
2636 foreach my $snapname (keys %{$conf->{snapshots
}}) {
2637 my $snap = $conf->{snapshots
}->{$snapname};
2638 &$test_volid($snap->{vmstate
}, 0);
2639 foreach_drive
($snap, sub {
2640 my ($ds, $drive) = @_;
2641 &$test_volid($drive->{file
}, drive_is_cdrom
($drive));
2645 foreach my $volid (keys %$volhash) {
2646 &$func($volid, $volhash->{$volid});
2650 sub vga_conf_has_spice
{
2653 return 0 if !$vga || $vga !~ m/^qxl([234])?$/;
2658 sub config_to_command
{
2659 my ($storecfg, $vmid, $conf, $defaults, $forcemachine) = @_;
2662 my $globalFlags = [];
2663 my $machineFlags = [];
2669 my $kvmver = kvm_user_version
();
2670 my $vernum = 0; # unknown
2671 my $ostype = $conf->{ostype
};
2672 if ($kvmver =~ m/^(\d+)\.(\d+)$/) {
2673 $vernum = $1*1000000+$2*1000;
2674 } elsif ($kvmver =~ m/^(\d+)\.(\d+)\.(\d+)$/) {
2675 $vernum = $1*1000000+$2*1000+$3;
2678 die "detected old qemu-kvm binary ($kvmver)\n" if $vernum < 15000;
2680 my $have_ovz = -f
'/proc/vz/vestat';
2682 my $q35 = machine_type_is_q35
($conf);
2683 my $hotplug_features = parse_hotplug_features
(defined($conf->{hotplug
}) ?
$conf->{hotplug
} : '1');
2684 my $machine_type = $forcemachine || $conf->{machine
};
2685 my $use_old_bios_files = undef;
2686 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
2688 my $cpuunits = defined($conf->{cpuunits
}) ?
2689 $conf->{cpuunits
} : $defaults->{cpuunits
};
2691 push @$cmd, '/usr/bin/systemd-run';
2692 push @$cmd, '--scope';
2693 push @$cmd, '--slice', "qemu";
2694 push @$cmd, '--unit', $vmid;
2695 # set KillMode=none, so that systemd don't kill those scopes
2696 # at shutdown (pve-manager service should stop the VMs instead)
2697 push @$cmd, '-p', "KillMode=none";
2698 push @$cmd, '-p', "CPUShares=$cpuunits";
2699 if ($conf->{cpulimit
}) {
2700 my $cpulimit = int($conf->{cpulimit
} * 100);
2701 push @$cmd, '-p', "CPUQuota=$cpulimit\%";
2704 push @$cmd, '/usr/bin/kvm';
2706 push @$cmd, '-id', $vmid;
2710 my $qmpsocket = qmp_socket
($vmid);
2711 push @$cmd, '-chardev', "socket,id=qmp,path=$qmpsocket,server,nowait";
2712 push @$cmd, '-mon', "chardev=qmp,mode=control";
2715 push @$cmd, '-pidfile' , pidfile_name
($vmid);
2717 push @$cmd, '-daemonize';
2719 if ($conf->{smbios1
}) {
2720 push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
2723 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
2724 my $ovmfvar = "OVMF_VARS-pure-efi.fd";
2725 my $ovmfvar_src = "/usr/share/kvm/$ovmfvar";
2726 my $ovmfvar_dst = "/tmp/$vmid-$ovmfvar";
2727 PVE
::Tools
::file_copy
($ovmfvar_src, $ovmfvar_dst, 256*1024);
2728 push @$cmd, '-drive', "if=pflash,format=raw,readonly,file=/usr/share/kvm/OVMF-pure-efi.fd";
2729 push @$cmd, '-drive', "if=pflash,format=raw,file=$ovmfvar_dst";
2733 # the q35 chipset support native usb2, so we enable usb controller
2734 # by default for this machine type
2735 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35.cfg';
2737 $pciaddr = print_pci_addr
("piix3", $bridges);
2738 push @$devices, '-device', "piix3-usb-uhci,id=uhci$pciaddr.0x2";
2741 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
2742 next if !$conf->{"usb$i"};
2743 my $d = eval { PVE
::JSONSchema
::parse_property_string
($usbdesc->{format
},$conf->{"usb$i"}) };
2744 next if !$d || $d->{usb3
}; # do not add usb2 controller if we have only usb3 devices
2747 # include usb device config
2748 push @$devices, '-readconfig', '/usr/share/qemu-server/pve-usb.cfg' if $use_usb2;
2751 # add usb3 controller if needed
2754 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
2755 next if !$conf->{"usb$i"};
2756 my $d = eval { PVE
::JSONSchema
::parse_property_string
($usbdesc->{format
},$conf->{"usb$i"}) };
2757 next if !$d || !$d->{usb3
};
2761 $pciaddr = print_pci_addr
("xhci", $bridges);
2762 push @$devices, '-device', "nec-usb-xhci,id=xhci$pciaddr" if $use_usb3;
2764 my $vga = $conf->{vga
};
2766 my $qxlnum = vga_conf_has_spice
($vga);
2767 $vga = 'qxl' if $qxlnum;
2770 if ($conf->{ostype
} && ($conf->{ostype
} eq 'win8' ||
2771 $conf->{ostype
} eq 'win7' ||
2772 $conf->{ostype
} eq 'w2k8')) {
2779 # enable absolute mouse coordinates (needed by vnc)
2781 if (defined($conf->{tablet
})) {
2782 $tablet = $conf->{tablet
};
2784 $tablet = $defaults->{tablet
};
2785 $tablet = 0 if $qxlnum; # disable for spice because it is not needed
2786 $tablet = 0 if $vga =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
2789 push @$devices, '-device', print_tabletdevice_full
($conf) if $tablet;
2793 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
2794 my $d = parse_hostpci
($conf->{"hostpci$i"});
2797 my $pcie = $d->{pcie
};
2799 die "q35 machine model is not enabled" if !$q35;
2800 $pciaddr = print_pcie_addr
("hostpci$i");
2802 $pciaddr = print_pci_addr
("hostpci$i", $bridges);
2805 my $rombar = $d->{rombar
} && $d->{rombar
} eq 'off' ?
",rombar=0" : "";
2806 my $xvga = $d->{'x-vga'} && $d->{'x-vga'} eq 'on' ?
",x-vga=on" : "";
2807 if ($xvga && $xvga ne '') {
2810 if ($ostype eq 'win7' || $ostype eq 'win8' || $ostype eq 'w2k8') {
2811 push @$cpuFlags , 'hv_vendor_id=proxmox';
2813 if ($conf->{bios
} && $conf->{bios
} eq 'ovmf') {
2817 my $pcidevices = $d->{pciid
};
2818 my $multifunction = 1 if @$pcidevices > 1;
2821 foreach my $pcidevice (@$pcidevices) {
2823 my $id = "hostpci$i";
2824 $id .= ".$j" if $multifunction;
2825 my $addr = $pciaddr;
2826 $addr .= ".$j" if $multifunction;
2827 my $devicestr = "vfio-pci,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
2830 $devicestr .= "$rombar$xvga";
2831 $devicestr .= ",multifunction=on" if $multifunction;
2834 push @$devices, '-device', $devicestr;
2840 for (my $i = 0; $i < $MAX_USB_DEVICES; $i++) {
2841 next if !$conf->{"usb$i"};
2842 my $d = eval { PVE
::JSONSchema
::parse_property_string
($usbdesc->{format
},$conf->{"usb$i"}) };
2845 # if it is a usb3 device, attach it to the xhci controller, else omit the bus option
2847 if (defined($d->{usb3
}) && $d->{usb3
}) {
2848 $usbbus = ',bus=xhci.0';
2851 if (defined($d->{host
})) {
2852 $d = parse_usb_device
($d->{host
});
2853 if (defined($d->{vendorid
}) && defined($d->{productid
})) {
2854 push @$devices, '-device', "usb-host$usbbus,vendorid=0x$d->{vendorid},productid=0x$d->{productid}";
2855 } elsif (defined($d->{hostbus
}) && defined($d->{hostport
})) {
2856 push @$devices, '-device', "usb-host$usbbus,hostbus=$d->{hostbus},hostport=$d->{hostport}";
2857 } elsif (defined($d->{spice
}) && $d->{spice
}) {
2858 # usb redir support for spice, currently no usb3
2859 push @$devices, '-chardev', "spicevmc,id=usbredirchardev$i,name=usbredir";
2860 push @$devices, '-device', "usb-redir,chardev=usbredirchardev$i,id=usbredirdev$i,bus=ehci.0";
2866 for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
2867 if (my $path = $conf->{"serial$i"}) {
2868 if ($path eq 'socket') {
2869 my $socket = "/var/run/qemu-server/${vmid}.serial$i";
2870 push @$devices, '-chardev', "socket,id=serial$i,path=$socket,server,nowait";
2871 push @$devices, '-device', "isa-serial,chardev=serial$i";
2873 die "no such serial device\n" if ! -c
$path;
2874 push @$devices, '-chardev', "tty,id=serial$i,path=$path";
2875 push @$devices, '-device', "isa-serial,chardev=serial$i";
2881 for (my $i = 0; $i < $MAX_PARALLEL_PORTS; $i++) {
2882 if (my $path = $conf->{"parallel$i"}) {
2883 die "no such parallel device\n" if ! -c
$path;
2884 my $devtype = $path =~ m!^/dev/usb/lp! ?
'tty' : 'parport';
2885 push @$devices, '-chardev', "$devtype,id=parallel$i,path=$path";
2886 push @$devices, '-device', "isa-parallel,chardev=parallel$i";
2890 my $vmname = $conf->{name
} || "vm$vmid";
2892 push @$cmd, '-name', $vmname;
2895 $sockets = $conf->{smp
} if $conf->{smp
}; # old style - no longer iused
2896 $sockets = $conf->{sockets
} if $conf->{sockets
};
2898 my $cores = $conf->{cores
} || 1;
2900 my $maxcpus = $sockets * $cores;
2902 my $vcpus = $conf->{vcpus
} ?
$conf->{vcpus
} : $maxcpus;
2904 my $allowed_vcpus = $cpuinfo->{cpus
};
2906 die "MAX $allowed_vcpus vcpus allowed per VM on this node\n"
2907 if ($allowed_vcpus < $maxcpus);
2909 push @$cmd, '-smp', "$vcpus,sockets=$sockets,cores=$cores,maxcpus=$maxcpus";
2911 push @$cmd, '-nodefaults';
2913 my $bootorder = $conf->{boot
} || $confdesc->{boot
}->{default};
2915 my $bootindex_hash = {};
2917 foreach my $o (split(//, $bootorder)) {
2918 $bootindex_hash->{$o} = $i*100;
2922 push @$cmd, '-boot', "menu=on,strict=on,reboot-timeout=1000";
2924 push @$cmd, '-no-acpi' if defined($conf->{acpi
}) && $conf->{acpi
} == 0;
2926 push @$cmd, '-no-reboot' if defined($conf->{reboot
}) && $conf->{reboot
} == 0;
2928 push @$cmd, '-vga', $vga if $vga && $vga !~ m/^serial\d+$/; # for kvm 77 and later
2930 if ($vga && $vga !~ m/^serial\d+$/ && $vga ne 'none'){
2931 my $socket = vnc_socket
($vmid);
2932 push @$cmd, '-vnc', "unix:$socket,x509,password";
2934 push @$cmd, '-nographic';
2938 my $tdf = defined($conf->{tdf
}) ?
$conf->{tdf
} : $defaults->{tdf
};
2940 my $nokvm = defined($conf->{kvm
}) && $conf->{kvm
} == 0 ?
1 : 0;
2941 my $useLocaltime = $conf->{localtime};
2944 # other, wxp, w2k, w2k3, w2k8, wvista, win7, win8, l24, l26, solaris
2946 if ($ostype =~ m/^w/) { # windows
2947 $useLocaltime = 1 if !defined($conf->{localtime});
2949 # use time drift fix when acpi is enabled
2950 if (!(defined($conf->{acpi
}) && $conf->{acpi
} == 0)) {
2951 $tdf = 1 if !defined($conf->{tdf
});
2955 if ($ostype eq 'win7' || $ostype eq 'win8' || $ostype eq 'w2k8' ||
2956 $ostype eq 'wvista') {
2957 push @$globalFlags, 'kvm-pit.lost_tick_policy=discard';
2958 push @$cmd, '-no-hpet';
2959 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
2960 push @$cpuFlags , 'hv_spinlocks=0x1fff' if !$nokvm;
2961 push @$cpuFlags , 'hv_vapic' if !$nokvm;
2962 push @$cpuFlags , 'hv_time' if !$nokvm;
2965 push @$cpuFlags , 'hv_spinlocks=0xffff' if !$nokvm;
2969 if ($ostype eq 'win7' || $ostype eq 'win8') {
2970 push @$cpuFlags , 'hv_relaxed' if !$nokvm;
2974 push @$rtcFlags, 'driftfix=slew' if $tdf;
2977 push @$machineFlags, 'accel=tcg';
2979 die "No accelerator found!\n" if !$cpuinfo->{hvm
};
2982 if ($machine_type) {
2983 push @$machineFlags, "type=${machine_type}";
2986 if ($conf->{startdate
}) {
2987 push @$rtcFlags, "base=$conf->{startdate}";
2988 } elsif ($useLocaltime) {
2989 push @$rtcFlags, 'base=localtime';
2992 my $cpu = $nokvm ?
"qemu64" : "kvm64";
2993 if (my $cputype = $conf->{cpu
}) {
2994 my $cpuconf = PVE
::JSONSchema
::parse_property_string
($cpudesc, $cputype)
2995 or die "Cannot parse cpu description: $cputype\n";
2996 $cpu = $cpuconf->{cputype
};
2997 $kvm_off = 1 if $cpuconf->{hidden
};
3000 push @$cpuFlags , '+lahf_lm' if $cpu eq 'kvm64';
3002 push @$cpuFlags , '-x2apic'
3003 if $conf->{ostype
} && $conf->{ostype
} eq 'solaris';
3005 push @$cpuFlags, '+sep' if $cpu eq 'kvm64' || $cpu eq 'kvm32';
3007 push @$cpuFlags, '-rdtscp' if $cpu =~ m/^Opteron/;
3009 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3011 push @$cpuFlags , '+kvm_pv_unhalt' if !$nokvm;
3012 push @$cpuFlags , '+kvm_pv_eoi' if !$nokvm;
3015 push @$cpuFlags, 'enforce' if $cpu ne 'host' && !$nokvm;
3017 push @$cpuFlags, 'kvm=off' if $kvm_off;
3019 $cpu .= "," . join(',', @$cpuFlags) if scalar(@$cpuFlags);
3021 push @$cmd, '-cpu', $cpu;
3023 my $memory = $conf->{memory
} || $defaults->{memory
};
3024 my $static_memory = 0;
3025 my $dimm_memory = 0;
3027 if ($hotplug_features->{memory
}) {
3028 die "Numa need to be enabled for memory hotplug\n" if !$conf->{numa
};
3029 die "Total memory is bigger than ${MAX_MEM}MB\n" if $memory > $MAX_MEM;
3030 $static_memory = $STATICMEM;
3031 die "minimum memory must be ${static_memory}MB\n" if($memory < $static_memory);
3032 $dimm_memory = $memory - $static_memory;
3033 push @$cmd, '-m', "size=${static_memory},slots=255,maxmem=${MAX_MEM}M";
3037 $static_memory = $memory;
3038 push @$cmd, '-m', $static_memory;
3041 if ($conf->{numa
}) {
3043 my $numa_totalmemory = undef;
3044 for (my $i = 0; $i < $MAX_NUMA; $i++) {
3045 next if !$conf->{"numa$i"};
3046 my $numa = parse_numa
($conf->{"numa$i"});
3049 die "missing numa node$i memory value\n" if !$numa->{memory
};
3050 my $numa_memory = $numa->{memory
};
3051 $numa_totalmemory += $numa_memory;
3052 my $numa_object = "memory-backend-ram,id=ram-node$i,size=${numa_memory}M";
3055 my $cpus_start = $numa->{cpus
}->{start
};
3056 die "missing numa node$i cpus\n" if !defined($cpus_start);
3057 my $cpus_end = $numa->{cpus
}->{end
} if defined($numa->{cpus
}->{end
});
3058 my $cpus = $cpus_start;
3059 if (defined($cpus_end)) {
3060 $cpus .= "-$cpus_end";
3061 die "numa node$i : cpu range $cpus is incorrect\n" if $cpus_end <= $cpus_start;
3065 my $hostnodes_start = $numa->{hostnodes
}->{start
};
3066 if (defined($hostnodes_start)) {
3067 my $hostnodes_end = $numa->{hostnodes
}->{end
} if defined($numa->{hostnodes
}->{end
});
3068 my $hostnodes = $hostnodes_start;
3069 if (defined($hostnodes_end)) {
3070 $hostnodes .= "-$hostnodes_end";
3071 die "host node $hostnodes range is incorrect\n" if $hostnodes_end <= $hostnodes_start;
3074 my $hostnodes_end_range = defined($hostnodes_end) ?
$hostnodes_end : $hostnodes_start;
3075 for (my $i = $hostnodes_start; $i <= $hostnodes_end_range; $i++ ) {
3076 die "host numa node$i don't exist\n" if ! -d
"/sys/devices/system/node/node$i/";
3080 my $policy = $numa->{policy
};
3081 die "you need to define a policy for hostnode $hostnodes\n" if !$policy;
3082 $numa_object .= ",host-nodes=$hostnodes,policy=$policy";
3085 push @$cmd, '-object', $numa_object;
3086 push @$cmd, '-numa', "node,nodeid=$i,cpus=$cpus,memdev=ram-node$i";
3089 die "total memory for NUMA nodes must be equal to vm static memory\n"
3090 if $numa_totalmemory && $numa_totalmemory != $static_memory;
3092 #if no custom tology, we split memory and cores across numa nodes
3093 if(!$numa_totalmemory) {
3095 my $numa_memory = ($static_memory / $sockets) . "M";
3097 for (my $i = 0; $i < $sockets; $i++) {
3099 my $cpustart = ($cores * $i);
3100 my $cpuend = ($cpustart + $cores - 1) if $cores && $cores > 1;
3101 my $cpus = $cpustart;
3102 $cpus .= "-$cpuend" if $cpuend;
3104 push @$cmd, '-object', "memory-backend-ram,size=$numa_memory,id=ram-node$i";
3105 push @$cmd, '-numa', "node,nodeid=$i,cpus=$cpus,memdev=ram-node$i";
3110 if ($hotplug_features->{memory
}) {
3111 foreach_dimm
($conf, $vmid, $memory, $sockets, sub {
3112 my ($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory) = @_;
3113 push @$cmd, "-object" , "memory-backend-ram,id=mem-$name,size=${dimm_size}M";
3114 push @$cmd, "-device", "pc-dimm,id=$name,memdev=mem-$name,node=$numanode";
3116 #if dimm_memory is not aligned to dimm map
3117 if($current_size > $memory) {
3118 $conf->{memory
} = $current_size;
3119 PVE
::QemuConfig-
>write_config($vmid, $conf);
3124 push @$cmd, '-S' if $conf->{freeze
};
3126 # set keyboard layout
3127 my $kb = $conf->{keyboard
} || $defaults->{keyboard
};
3128 push @$cmd, '-k', $kb if $kb;
3131 #my $soundhw = $conf->{soundhw} || $defaults->{soundhw};
3132 #push @$cmd, '-soundhw', 'es1370';
3133 #push @$cmd, '-soundhw', $soundhw if $soundhw;
3135 if($conf->{agent
}) {
3136 my $qgasocket = qmp_socket
($vmid, 1);
3137 my $pciaddr = print_pci_addr
("qga0", $bridges);
3138 push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
3139 push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
3140 push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
3147 if ($conf->{ostype
} && $conf->{ostype
} =~ m/^w/){
3148 for(my $i = 1; $i < $qxlnum; $i++){
3149 my $pciaddr = print_pci_addr
("vga$i", $bridges);
3150 push @$cmd, '-device', "qxl,id=vga$i,ram_size=67108864,vram_size=33554432$pciaddr";
3153 # assume other OS works like Linux
3154 push @$cmd, '-global', 'qxl-vga.ram_size=134217728';
3155 push @$cmd, '-global', 'qxl-vga.vram_size=67108864';
3159 my $pciaddr = print_pci_addr
("spice", $bridges);
3161 my $nodename = PVE
::INotify
::nodename
();
3162 my $pfamily = PVE
::Tools
::get_host_address_family
($nodename);
3163 $spice_port = PVE
::Tools
::next_spice_port
($pfamily);
3165 push @$devices, '-spice', "tls-port=${spice_port},addr=localhost,tls-ciphers=DES-CBC3-SHA,seamless-migration=on";
3167 push @$devices, '-device', "virtio-serial,id=spice$pciaddr";
3168 push @$devices, '-chardev', "spicevmc,id=vdagent,name=vdagent";
3169 push @$devices, '-device', "virtserialport,chardev=vdagent,name=com.redhat.spice.0";
3172 # enable balloon by default, unless explicitly disabled
3173 if (!defined($conf->{balloon
}) || $conf->{balloon
}) {
3174 $pciaddr = print_pci_addr
("balloon0", $bridges);
3175 push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
3178 if ($conf->{watchdog
}) {
3179 my $wdopts = parse_watchdog
($conf->{watchdog
});
3180 $pciaddr = print_pci_addr
("watchdog", $bridges);
3181 my $watchdog = $wdopts->{model
} || 'i6300esb';
3182 push @$devices, '-device', "$watchdog$pciaddr";
3183 push @$devices, '-watchdog-action', $wdopts->{action
} if $wdopts->{action
};
3187 my $scsicontroller = {};
3188 my $ahcicontroller = {};
3189 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : $defaults->{scsihw
};
3191 # Add iscsi initiator name if available
3192 if (my $initiator = get_initiator_name
()) {
3193 push @$devices, '-iscsi', "initiator-name=$initiator";
3196 foreach_drive
($conf, sub {
3197 my ($ds, $drive) = @_;
3199 if (PVE
::Storage
::parse_volume_id
($drive->{file
}, 1)) {
3200 push @$vollist, $drive->{file
};
3203 $use_virtio = 1 if $ds =~ m/^virtio/;
3205 if (drive_is_cdrom
($drive)) {
3206 if ($bootindex_hash->{d
}) {
3207 $drive->{bootindex
} = $bootindex_hash->{d
};
3208 $bootindex_hash->{d
} += 1;
3211 if ($bootindex_hash->{c
}) {
3212 $drive->{bootindex
} = $bootindex_hash->{c
} if $conf->{bootdisk
} && ($conf->{bootdisk
} eq $ds);
3213 $bootindex_hash->{c
} += 1;
3217 if($drive->{interface
} eq 'virtio'){
3218 push @$cmd, '-object', "iothread,id=iothread-$ds" if $drive->{iothread
};
3221 if ($drive->{interface
} eq 'scsi') {
3223 my ($maxdev, $controller, $controller_prefix) = scsihw_infos
($conf, $drive);
3225 $pciaddr = print_pci_addr
("$controller_prefix$controller", $bridges);
3226 my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ?
"virtio-scsi-pci" : $scsihw;
3229 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{iothread
}){
3230 $iothread .= ",iothread=iothread-$controller_prefix$controller";
3231 push @$cmd, '-object', "iothread,id=iothread-$controller_prefix$controller";
3235 if($conf->{scsihw
} && $conf->{scsihw
} eq "virtio-scsi-single" && $drive->{queues
}){
3236 $queues = ",num_queues=$drive->{queues}";
3239 push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
3240 $scsicontroller->{$controller}=1;
3243 if ($drive->{interface
} eq 'sata') {
3244 my $controller = int($drive->{index} / $MAX_SATA_DISKS);
3245 $pciaddr = print_pci_addr
("ahci$controller", $bridges);
3246 push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
3247 $ahcicontroller->{$controller}=1;
3250 my $drive_cmd = print_drive_full
($storecfg, $vmid, $drive);
3251 push @$devices, '-drive',$drive_cmd;
3252 push @$devices, '-device', print_drivedevice_full
($storecfg, $conf, $vmid, $drive, $bridges);
3255 for (my $i = 0; $i < $MAX_NETS; $i++) {
3256 next if !$conf->{"net$i"};
3257 my $d = parse_net
($conf->{"net$i"});
3260 $use_virtio = 1 if $d->{model
} eq 'virtio';
3262 if ($bootindex_hash->{n
}) {
3263 $d->{bootindex
} = $bootindex_hash->{n
};
3264 $bootindex_hash->{n
} += 1;
3267 my $netdevfull = print_netdev_full
($vmid,$conf,$d,"net$i");
3268 push @$devices, '-netdev', $netdevfull;
3270 my $netdevicefull = print_netdevice_full
($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files);
3271 push @$devices, '-device', $netdevicefull;
3276 if (qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 3)) {
3281 $bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
3283 while (my ($k, $v) = each %$bridges) {
3284 $pciaddr = print_pci_addr
("pci.$k");
3285 unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
3290 if ($conf->{args
}) {
3291 my $aa = PVE
::Tools
::split_args
($conf->{args
});
3295 push @$cmd, @$devices;
3296 push @$cmd, '-rtc', join(',', @$rtcFlags)
3297 if scalar(@$rtcFlags);
3298 push @$cmd, '-machine', join(',', @$machineFlags)
3299 if scalar(@$machineFlags);
3300 push @$cmd, '-global', join(',', @$globalFlags)
3301 if scalar(@$globalFlags);
3303 return wantarray ?
($cmd, $vollist, $spice_port) : $cmd;
3308 return "${var_run_tmpdir}/$vmid.vnc";
3314 my $res = vm_mon_cmd
($vmid, 'query-spice');
3316 return $res->{'tls-port'} || $res->{'port'} || die "no spice port\n";
3320 my ($vmid, $qga) = @_;
3321 my $sockettype = $qga ?
'qga' : 'qmp';
3322 return "${var_run_tmpdir}/$vmid.$sockettype";
3327 return "${var_run_tmpdir}/$vmid.pid";
3330 sub vm_devices_list
{
3333 my $res = vm_mon_cmd
($vmid, 'query-pci');
3335 foreach my $pcibus (@$res) {
3336 foreach my $device (@{$pcibus->{devices
}}) {
3337 next if !$device->{'qdev_id'};
3338 if ($device->{'pci_bridge'}) {
3339 $devices->{$device->{'qdev_id'}} = 1;
3340 foreach my $bridge_device (@{$device->{'pci_bridge'}->{devices
}}) {
3341 next if !$bridge_device->{'qdev_id'};
3342 $devices->{$bridge_device->{'qdev_id'}} = 1;
3343 $devices->{$device->{'qdev_id'}}++;
3346 $devices->{$device->{'qdev_id'}} = 1;
3351 my $resblock = vm_mon_cmd
($vmid, 'query-block');
3352 foreach my $block (@$resblock) {
3353 if($block->{device
} =~ m/^drive-(\S+)/){
3358 my $resmice = vm_mon_cmd
($vmid, 'query-mice');
3359 foreach my $mice (@$resmice) {
3360 if ($mice->{name
} eq 'QEMU HID Tablet') {
3361 $devices->{tablet
} = 1;
3370 my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
3372 my $q35 = machine_type_is_q35
($conf);
3374 my $devices_list = vm_devices_list
($vmid);
3375 return 1 if defined($devices_list->{$deviceid});
3377 qemu_add_pci_bridge
($storecfg, $conf, $vmid, $deviceid); # add PCI bridge if we need it for the device
3379 if ($deviceid eq 'tablet') {
3381 qemu_deviceadd
($vmid, print_tabletdevice_full
($conf));
3383 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3385 qemu_iothread_add
($vmid, $deviceid, $device);
3387 qemu_driveadd
($storecfg, $vmid, $device);
3388 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3390 qemu_deviceadd
($vmid, $devicefull);
3391 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3393 eval { qemu_drivedel
($vmid, $deviceid); };
3398 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3401 my $scsihw = defined($conf->{scsihw
}) ?
$conf->{scsihw
} : "lsi";
3402 my $pciaddr = print_pci_addr
($deviceid);
3403 my $scsihw_type = $scsihw eq 'virtio-scsi-single' ?
"virtio-scsi-pci" : $scsihw;
3405 my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
3407 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{iothread
}) {
3408 qemu_iothread_add
($vmid, $deviceid, $device);
3409 $devicefull .= ",iothread=iothread-$deviceid";
3412 if($deviceid =~ m/^virtioscsi(\d+)$/ && $device->{queues
}) {
3413 $devicefull .= ",num_queues=$device->{queues}";
3416 qemu_deviceadd
($vmid, $devicefull);
3417 qemu_deviceaddverify
($vmid, $deviceid);
3419 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3421 qemu_findorcreatescsihw
($storecfg,$conf, $vmid, $device);
3422 qemu_driveadd
($storecfg, $vmid, $device);
3424 my $devicefull = print_drivedevice_full
($storecfg, $conf, $vmid, $device);
3425 eval { qemu_deviceadd
($vmid, $devicefull); };
3427 eval { qemu_drivedel
($vmid, $deviceid); };
3432 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3434 return undef if !qemu_netdevadd
($vmid, $conf, $device, $deviceid);
3436 my $machine_type = PVE
::QemuServer
::qemu_machine_pxe
($vmid, $conf);
3437 my $use_old_bios_files = undef;
3438 ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files
($machine_type);
3440 my $netdevicefull = print_netdevice_full
($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files);
3441 qemu_deviceadd
($vmid, $netdevicefull);
3442 eval { qemu_deviceaddverify
($vmid, $deviceid); };
3444 eval { qemu_netdevdel
($vmid, $deviceid); };
3449 } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
3452 my $pciaddr = print_pci_addr
($deviceid);
3453 my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
3455 qemu_deviceadd
($vmid, $devicefull);
3456 qemu_deviceaddverify
($vmid, $deviceid);
3459 die "can't hotplug device '$deviceid'\n";
3465 # fixme: this should raise exceptions on error!
3466 sub vm_deviceunplug
{
3467 my ($vmid, $conf, $deviceid) = @_;
3469 my $devices_list = vm_devices_list
($vmid);
3470 return 1 if !defined($devices_list->{$deviceid});
3472 die "can't unplug bootdisk" if $conf->{bootdisk
} && $conf->{bootdisk
} eq $deviceid;
3474 if ($deviceid eq 'tablet') {
3476 qemu_devicedel
($vmid, $deviceid);
3478 } elsif ($deviceid =~ m/^(virtio)(\d+)$/) {
3480 qemu_devicedel
($vmid, $deviceid);
3481 qemu_devicedelverify
($vmid, $deviceid);
3482 qemu_drivedel
($vmid, $deviceid);
3483 qemu_iothread_del
($conf, $vmid, $deviceid);
3485 } elsif ($deviceid =~ m/^(virtioscsi|scsihw)(\d+)$/) {
3487 qemu_devicedel
($vmid, $deviceid);
3488 qemu_devicedelverify
($vmid, $deviceid);
3489 qemu_iothread_del
($conf, $vmid, $deviceid);
3491 } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
3493 #qemu 2.3 segfault on drive_del with virtioscsi + iothread
3494 my $device = parse_drive
($deviceid, $conf->{$deviceid});
3495 die "virtioscsi with iothread is not hot-unplugglable currently" if $device->{iothread
};
3497 qemu_devicedel
($vmid, $deviceid);
3498 qemu_drivedel
($vmid, $deviceid);
3499 qemu_deletescsihw
($conf, $vmid, $deviceid);
3501 } elsif ($deviceid =~ m/^(net)(\d+)$/) {
3503 qemu_devicedel
($vmid, $deviceid);
3504 qemu_devicedelverify
($vmid, $deviceid);
3505 qemu_netdevdel
($vmid, $deviceid);
3508 die "can't unplug device '$deviceid'\n";
3514 sub qemu_deviceadd
{
3515 my ($vmid, $devicefull) = @_;
3517 $devicefull = "driver=".$devicefull;
3518 my %options = split(/[=,]/, $devicefull);
3520 vm_mon_cmd
($vmid, "device_add" , %options);
3523 sub qemu_devicedel
{
3524 my ($vmid, $deviceid) = @_;
3526 my $ret = vm_mon_cmd
($vmid, "device_del", id
=> $deviceid);
3529 sub qemu_iothread_add
{
3530 my($vmid, $deviceid, $device) = @_;
3532 if ($device->{iothread
}) {
3533 my $iothreads = vm_iothreads_list
($vmid);
3534 qemu_objectadd
($vmid, "iothread-$deviceid", "iothread") if !$iothreads->{"iothread-$deviceid"};
3538 sub qemu_iothread_del
{
3539 my($conf, $vmid, $deviceid) = @_;
3541 my $device = parse_drive
($deviceid, $conf->{$deviceid});
3542 if ($device->{iothread
}) {
3543 my $iothreads = vm_iothreads_list
($vmid);
3544 qemu_objectdel
($vmid, "iothread-$deviceid") if $iothreads->{"iothread-$deviceid"};
3548 sub qemu_objectadd
{
3549 my($vmid, $objectid, $qomtype) = @_;
3551 vm_mon_cmd
($vmid, "object-add", id
=> $objectid, "qom-type" => $qomtype);
3556 sub qemu_objectdel
{
3557 my($vmid, $objectid) = @_;
3559 vm_mon_cmd
($vmid, "object-del", id
=> $objectid);
3565 my ($storecfg, $vmid, $device) = @_;
3567 my $drive = print_drive_full
($storecfg, $vmid, $device);
3568 $drive =~ s/\\/\\\\/g;
3569 my $ret = vm_human_monitor_command
($vmid, "drive_add auto \"$drive\"");
3571 # If the command succeeds qemu prints: "OK
"
3572 return 1 if $ret =~ m/OK/s;
3574 die "adding drive failed
: $ret\n";
3578 my($vmid, $deviceid) = @_;
3580 my $ret = vm_human_monitor_command($vmid, "drive_del drive-
$deviceid");
3583 return 1 if $ret eq "";
3585 # NB: device not found errors mean the drive was auto-deleted and we ignore the error
3586 return 1 if $ret =~ m/Device \'.*?\' not found/s;
3588 die "deleting drive
$deviceid failed
: $ret\n";
3591 sub qemu_deviceaddverify {
3592 my ($vmid, $deviceid) = @_;
3594 for (my $i = 0; $i <= 5; $i++) {
3595 my $devices_list = vm_devices_list($vmid);
3596 return 1 if defined($devices_list->{$deviceid});
3600 die "error on hotplug device
'$deviceid'\n";
3604 sub qemu_devicedelverify {
3605 my ($vmid, $deviceid) = @_;
3607 # need to verify that the device is correctly removed as device_del
3608 # is async and empty return is not reliable
3610 for (my $i = 0; $i <= 5; $i++) {
3611 my $devices_list = vm_devices_list($vmid);
3612 return 1 if !defined($devices_list->{$deviceid});
3616 die "error on hot-unplugging device
'$deviceid'\n";
3619 sub qemu_findorcreatescsihw {
3620 my ($storecfg, $conf, $vmid, $device) = @_;
3622 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3624 my $scsihwid="$controller_prefix$controller";
3625 my $devices_list = vm_devices_list($vmid);
3627 if(!defined($devices_list->{$scsihwid})) {
3628 vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device);
3634 sub qemu_deletescsihw {
3635 my ($conf, $vmid, $opt) = @_;
3637 my $device = parse_drive($opt, $conf->{$opt});
3639 if ($conf->{scsihw} && ($conf->{scsihw} eq 'virtio-scsi-single')) {
3640 vm_deviceunplug($vmid, $conf, "virtioscsi
$device->{index}");
3644 my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
3646 my $devices_list = vm_devices_list($vmid);
3647 foreach my $opt (keys %{$devices_list}) {
3648 if (PVE::QemuServer::is_valid_drivename($opt)) {
3649 my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
3650 if($drive->{interface} eq 'scsi' && $drive->{index} < (($maxdev-1)*($controller+1))) {
3656 my $scsihwid="scsihw
$controller";
3658 vm_deviceunplug($vmid, $conf, $scsihwid);
3663 sub qemu_add_pci_bridge {
3664 my ($storecfg, $conf, $vmid, $device) = @_;
3670 print_pci_addr($device, $bridges);
3672 while (my ($k, $v) = each %$bridges) {
3675 return 1 if !defined($bridgeid) || $bridgeid < 1;
3677 my $bridge = "pci
.$bridgeid";
3678 my $devices_list = vm_devices_list($vmid);
3680 if (!defined($devices_list->{$bridge})) {
3681 vm_deviceplug($storecfg, $conf, $vmid, $bridge);
3687 sub qemu_set_link_status {
3688 my ($vmid, $device, $up) = @_;
3690 vm_mon_cmd($vmid, "set_link
", name => $device,
3691 up => $up ? JSON::true : JSON::false);
3694 sub qemu_netdevadd {
3695 my ($vmid, $conf, $device, $deviceid) = @_;
3697 my $netdev = print_netdev_full($vmid, $conf, $device, $deviceid, 1);
3698 my %options = split(/[=,]/, $netdev);
3700 vm_mon_cmd($vmid, "netdev_add
", %options);
3704 sub qemu_netdevdel {
3705 my ($vmid, $deviceid) = @_;
3707 vm_mon_cmd($vmid, "netdev_del
", id => $deviceid);
3710 sub qemu_cpu_hotplug {
3711 my ($vmid, $conf, $vcpus) = @_;
3714 $sockets = $conf->{smp} if $conf->{smp}; # old style - no longer iused
3715 $sockets = $conf->{sockets} if $conf->{sockets};
3716 my $cores = $conf->{cores} || 1;
3717 my $maxcpus = $sockets * $cores;
3719 $vcpus = $maxcpus if !$vcpus;
3721 die "you can
't add more vcpus than maxcpus\n"
3722 if $vcpus > $maxcpus;
3724 my $currentvcpus = $conf->{vcpus} || $maxcpus;
3725 die "online cpu unplug is not yet possible\n"
3726 if $vcpus < $currentvcpus;
3728 my $currentrunningvcpus = vm_mon_cmd($vmid, "query-cpus");
3729 die "vcpus in running vm is different than configuration\n"
3730 if scalar(@{$currentrunningvcpus}) != $currentvcpus;
3732 for (my $i = $currentvcpus; $i < $vcpus; $i++) {
3733 vm_mon_cmd($vmid, "cpu-add", id => int($i));
3737 sub qemu_memory_hotplug {
3738 my ($vmid, $conf, $defaults, $opt, $value) = @_;
3740 return $value if !check_running($vmid);
3742 my $memory = $conf->{memory} || $defaults->{memory};
3743 $value = $defaults->{memory} if !$value;
3744 return $value if $value == $memory;
3746 my $static_memory = $STATICMEM;
3747 my $dimm_memory = $memory - $static_memory;
3749 die "memory can't be lower than
$static_memory MB
" if $value < $static_memory;
3750 die "you cannot add more memory than
$MAX_MEM MB
!\n" if $memory > $MAX_MEM;
3754 $sockets = $conf->{sockets} if $conf->{sockets};
3756 if($value > $memory) {
3758 foreach_dimm($conf, $vmid, $value, $sockets, sub {
3759 my ($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory) = @_;
3761 return if $current_size <= $conf->{memory};
3763 eval { vm_mon_cmd($vmid, "object-add
", 'qom-type' => "memory-backend-ram
", id => "mem-
$name", props => { size => int($dimm_size*1024*1024) } ) };
3765 eval { qemu_objectdel($vmid, "mem-
$name"); };
3769 eval { vm_mon_cmd($vmid, "device_add
", driver => "pc-dimm
", id => "$name", memdev => "mem-
$name", node => $numanode) };
3771 eval { qemu_objectdel($vmid, "mem-
$name"); };
3774 #update conf after each succesful module hotplug
3775 $conf->{memory} = $current_size;
3776 PVE::QemuConfig->write_config($vmid, $conf);
3781 foreach_reverse_dimm($conf, $vmid, $value, $sockets, sub {
3782 my ($conf, $vmid, $name, $dimm_size, $numanode, $current_size, $memory) = @_;
3784 return if $current_size >= $conf->{memory};
3785 print "try to unplug memory dimm
$name\n";
3789 eval { qemu_devicedel($vmid, $name) };
3791 my $dimm_list = qemu_dimm_list($vmid);
3792 last if !$dimm_list->{$name};
3793 raise_param_exc({ $name => "error unplug memory module
" }) if $retry > 5;
3797 #update conf after each succesful module unplug
3798 $conf->{memory} = $current_size;
3800 eval { qemu_objectdel($vmid, "mem-
$name"); };
3801 PVE::QemuConfig->write_config($vmid, $conf);
3806 sub qemu_dimm_list {
3809 my $dimmarray = vm_mon_cmd_nocheck($vmid, "query-memory-devices
");
3812 foreach my $dimm (@$dimmarray) {
3814 $dimms->{$dimm->{data}->{id}}->{id} = $dimm->{data}->{id};
3815 $dimms->{$dimm->{data}->{id}}->{node} = $dimm->{data}->{node};
3816 $dimms->{$dimm->{data}->{id}}->{addr} = $dimm->{data}->{addr};
3817 $dimms->{$dimm->{data}->{id}}->{size} = $dimm->{data}->{size};
3818 $dimms->{$dimm->{data}->{id}}->{slot} = $dimm->{data}->{slot};
3823 sub qemu_block_set_io_throttle {
3824 my ($vmid, $deviceid,
3825 $bps, $bps_rd, $bps_wr, $iops, $iops_rd, $iops_wr,
3826 $bps_max, $bps_rd_max, $bps_wr_max, $iops_max, $iops_rd_max, $iops_wr_max) = @_;
3828 return if !check_running($vmid) ;
3830 vm_mon_cmd($vmid, "block_set_io_throttle
", device => $deviceid,
3832 bps_rd => int($bps_rd),
3833 bps_wr => int($bps_wr),
3835 iops_rd => int($iops_rd),
3836 iops_wr => int($iops_wr),
3837 bps_max => int($bps_max),
3838 bps_rd_max => int($bps_rd_max),
3839 bps_wr_max => int($bps_wr_max),
3840 iops_max => int($iops_max),
3841 iops_rd_max => int($iops_rd_max),
3842 iops_wr_max => int($iops_wr_max)
3847 # old code, only used to shutdown old VM after update
3849 my ($fh, $timeout) = @_;
3851 my $sel = new IO::Select;
3858 while (scalar (@ready = $sel->can_read($timeout))) {
3860 if ($count = $fh->sysread($buf, 8192)) {
3861 if ($buf =~ /^(.*)\(qemu\) $/s) {
3868 if (!defined($count)) {
3875 die "monitor
read timeout
\n" if !scalar(@ready);
3880 # old code, only used to shutdown old VM after update
3881 sub vm_monitor_command {
3882 my ($vmid, $cmdstr, $nocheck) = @_;
3887 die "VM
$vmid not running
\n" if !check_running($vmid, $nocheck);
3889 my $sname = "${var_run_tmpdir
}/$vmid.mon
";
3891 my $sock = IO::Socket::UNIX->new( Peer => $sname ) ||
3892 die "unable to
connect to VM
$vmid socket - $!\n";
3896 # hack: migrate sometime blocks the monitor (when migrate_downtime
3898 if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
3899 $timeout = 60*60; # 1 hour
3903 my $data = __read_avail($sock, $timeout);
3905 if ($data !~ m/^QEMU\s+(\S+)\s+monitor\s/) {
3906 die "got unexpected qemu monitor banner
\n";
3909 my $sel = new IO::Select;
3912 if (!scalar(my @ready = $sel->can_write($timeout))) {
3913 die "monitor
write error
- timeout
";
3916 my $fullcmd = "$cmdstr\r";
3918 # syslog('info', "VM
$vmid monitor command
: $cmdstr");
3921 if (!($b = $sock->syswrite($fullcmd)) || ($b != length($fullcmd))) {
3922 die "monitor
write error
- $!";
3925 return if ($cmdstr eq 'q') || ($cmdstr eq 'quit');
3929 if ($cmdstr =~ m/^(info\s+migrate|migrate\s)/) {
3930 $timeout = 60*60; # 1 hour
3931 } elsif ($cmdstr =~ m/^(eject|change)/) {
3932 $timeout = 60; # note: cdrom mount command is slow
3934 if ($res = __read_avail($sock, $timeout)) {
3936 my @lines = split("\r?
\n", $res);
3938 shift @lines if $lines[0] !~ m/^unknown command/; # skip echo
3940 $res = join("\n", @lines);
3948 syslog("err
", "VM
$vmid monitor command failed
- $err");
3955 sub qemu_block_resize {
3956 my ($vmid, $deviceid, $storecfg, $volid, $size) = @_;
3958 my $running = check_running($vmid);
3960 return if !PVE::Storage::volume_resize($storecfg, $volid, $size, $running);
3962 return if !$running;
3964 vm_mon_cmd($vmid, "block_resize
", device => $deviceid, size => int($size));
3968 sub qemu_volume_snapshot {
3969 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
3971 my $running = check_running($vmid);
3973 if ($running && do_snapshots_with_qemu($storecfg, $volid)){
3974 vm_mon_cmd($vmid, "snapshot-drive
", device => $deviceid, name => $snap);
3976 PVE::Storage::volume_snapshot($storecfg, $volid, $snap);
3980 sub qemu_volume_snapshot_delete {
3981 my ($vmid, $deviceid, $storecfg, $volid, $snap) = @_;
3983 my $running = check_running($vmid);
3985 return if !PVE::Storage::volume_snapshot_delete($storecfg, $volid, $snap, $running);
3987 return if !$running;
3989 vm_mon_cmd($vmid, "delete-drive-snapshot
", device => $deviceid, name => $snap);
3992 sub set_migration_caps {
3998 "auto-converge
" => 1,
4000 "x-rdma-pin-all
" => 0,
4005 my $supported_capabilities = vm_mon_cmd_nocheck($vmid, "query-migrate-capabilities
");
4007 for my $supported_capability (@$supported_capabilities) {
4009 capability => $supported_capability->{capability},
4010 state => $enabled_cap->{$supported_capability->{capability}} ? JSON::true : JSON::false,
4014 vm_mon_cmd_nocheck($vmid, "migrate-set-capabilities
", capabilities => $cap_ref);
4017 my $fast_plug_option = {
4026 # hotplug changes in [PENDING]
4027 # $selection hash can be used to only apply specified options, for
4028 # example: { cores => 1 } (only apply changed 'cores')
4029 # $errors ref is used to return error messages
4030 sub vmconfig_hotplug_pending {
4031 my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
4033 my $defaults = load_defaults();
4035 # commit values which do not have any impact on running VM first
4036 # Note: those option cannot raise errors, we we do not care about
4037 # $selection and always apply them.
4039 my $add_error = sub {
4040 my ($opt, $msg) = @_;
4041 $errors->{$opt} = "hotplug problem
- $msg";
4045 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4046 if ($fast_plug_option->{$opt}) {
4047 $conf->{$opt} = $conf->{pending}->{$opt};
4048 delete $conf->{pending}->{$opt};
4054 PVE::QemuConfig->write_config($vmid, $conf);
4055 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4058 my $hotplug_features = parse_hotplug_features(defined($conf->{hotplug}) ? $conf->{hotplug} : '1');
4060 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4061 while (my ($opt, $force) = each %$pending_delete_hash) {
4062 next if $selection && !$selection->{$opt};
4064 if ($opt eq 'hotplug') {
4065 die "skip
\n" if ($conf->{hotplug} =~ /memory/);
4066 } elsif ($opt eq 'tablet') {
4067 die "skip
\n" if !$hotplug_features->{usb};
4068 if ($defaults->{tablet}) {
4069 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4071 vm_deviceunplug($vmid, $conf, $opt);
4073 } elsif ($opt eq 'vcpus') {
4074 die "skip
\n" if !$hotplug_features->{cpu};
4075 qemu_cpu_hotplug($vmid, $conf, undef);
4076 } elsif ($opt eq 'balloon') {
4077 # enable balloon device is not hotpluggable
4078 die "skip
\n" if !defined($conf->{balloon}) || $conf->{balloon};
4079 } elsif ($fast_plug_option->{$opt}) {
4081 } elsif ($opt =~ m/^net(\d+)$/) {
4082 die "skip
\n" if !$hotplug_features->{network};
4083 vm_deviceunplug($vmid, $conf, $opt);
4084 } elsif (is_valid_drivename($opt)) {
4085 die "skip
\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
4086 vm_deviceunplug($vmid, $conf, $opt);
4087 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4088 } elsif ($opt =~ m/^memory$/) {
4089 die "skip
\n" if !$hotplug_features->{memory};
4090 qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
4091 } elsif ($opt eq 'cpuunits') {
4092 cgroups_write("cpu
", $vmid, "cpu
.shares
", $defaults->{cpuunits});
4093 } elsif ($opt eq 'cpulimit') {
4094 cgroups_write("cpu
", $vmid, "cpu
.cfs_quota_us
", -1);
4100 &$add_error($opt, $err) if $err ne "skip
\n";
4102 # save new config if hotplug was successful
4103 delete $conf->{$opt};
4104 vmconfig_undelete_pending_option($conf, $opt);
4105 PVE::QemuConfig->write_config($vmid, $conf);
4106 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4110 foreach my $opt (keys %{$conf->{pending}}) {
4111 next if $selection && !$selection->{$opt};
4112 my $value = $conf->{pending}->{$opt};
4114 if ($opt eq 'hotplug') {
4115 die "skip
\n" if ($value =~ /memory/) || ($value !~ /memory/ && $conf->{hotplug} =~ /memory/);
4116 } elsif ($opt eq 'tablet') {
4117 die "skip
\n" if !$hotplug_features->{usb};
4119 vm_deviceplug($storecfg, $conf, $vmid, $opt);
4120 } elsif ($value == 0) {
4121 vm_deviceunplug($vmid, $conf, $opt);
4123 } elsif ($opt eq 'vcpus') {
4124 die "skip
\n" if !$hotplug_features->{cpu};
4125 qemu_cpu_hotplug($vmid, $conf, $value);
4126 } elsif ($opt eq 'balloon') {
4127 # enable/disable balloning device is not hotpluggable
4128 my $old_balloon_enabled = !!(!defined($conf->{balloon}) || $conf->{balloon});
4129 my $new_balloon_enabled = !!(!defined($conf->{pending}->{balloon}) || $conf->{pending}->{balloon});
4130 die "skip
\n" if $old_balloon_enabled != $new_balloon_enabled;
4132 # allow manual ballooning if shares is set to zero
4133 if ((defined($conf->{shares}) && ($conf->{shares} == 0))) {
4134 my $balloon = $conf->{pending}->{balloon} || $conf->{memory} || $defaults->{memory};
4135 vm_mon_cmd($vmid, "balloon
", value => $balloon*1024*1024);
4137 } elsif ($opt =~ m/^net(\d+)$/) {
4138 # some changes can be done without hotplug
4139 vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
4140 $vmid, $opt, $value);
4141 } elsif (is_valid_drivename($opt)) {
4142 # some changes can be done without hotplug
4143 vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
4144 $vmid, $opt, $value, 1);
4145 } elsif ($opt =~ m/^memory$/) { #dimms
4146 die "skip
\n" if !$hotplug_features->{memory};
4147 $value = qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
4148 } elsif ($opt eq 'cpuunits') {
4149 cgroups_write("cpu
", $vmid, "cpu
.shares
", $conf->{pending}->{$opt});
4150 } elsif ($opt eq 'cpulimit') {
4151 my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
4152 cgroups_write("cpu
", $vmid, "cpu
.cfs_quota_us
", $cpulimit);
4154 die "skip
\n"; # skip non-hot-pluggable options
4158 &$add_error($opt, $err) if $err ne "skip
\n";
4160 # save new config if hotplug was successful
4161 $conf->{$opt} = $value;
4162 delete $conf->{pending}->{$opt};
4163 PVE::QemuConfig->write_config($vmid, $conf);
4164 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4169 sub try_deallocate_drive {
4170 my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
4172 if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
4173 my $volid = $drive->{file};
4174 if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
4175 my $sid = PVE::Storage::parse_volume_id($volid);
4176 $rpcenv->check($authuser, "/storage/$sid", ['Datastore.AllocateSpace']);
4178 # check if the disk is really unused
4179 die "unable to
delete '$volid' - volume
is still
in use (snapshot?
)\n"
4180 if is_volume_in_use($storecfg, $conf, $key, $volid);
4181 PVE::Storage::vdisk_free($storecfg, $volid);
4184 # If vm is not owner of this disk remove from config
4192 sub vmconfig_delete_or_detach_drive {
4193 my ($vmid, $storecfg, $conf, $opt, $force) = @_;
4195 my $drive = parse_drive($opt, $conf->{$opt});
4197 my $rpcenv = PVE::RPCEnvironment::get();
4198 my $authuser = $rpcenv->get_user();
4201 $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.Disk']);
4202 try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
4204 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
4208 sub vmconfig_apply_pending {
4209 my ($vmid, $conf, $storecfg) = @_;
4213 my $pending_delete_hash = split_flagged_list($conf->{pending}->{delete});
4214 while (my ($opt, $force) = each %$pending_delete_hash) {
4215 die "internal error
" if $opt =~ m/^unused/;
4216 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4217 if (!defined($conf->{$opt})) {
4218 vmconfig_undelete_pending_option($conf, $opt);
4219 PVE::QemuConfig->write_config($vmid, $conf);
4220 } elsif (is_valid_drivename($opt)) {
4221 vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
4222 vmconfig_undelete_pending_option($conf, $opt);
4223 delete $conf->{$opt};
4224 PVE::QemuConfig->write_config($vmid, $conf);
4226 vmconfig_undelete_pending_option($conf, $opt);
4227 delete $conf->{$opt};
4228 PVE::QemuConfig->write_config($vmid, $conf);
4232 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4234 foreach my $opt (keys %{$conf->{pending}}) { # add/change
4235 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4237 if (defined($conf->{$opt}) && ($conf->{$opt} eq $conf->{pending}->{$opt})) {
4238 # skip if nothing changed
4239 } elsif (is_valid_drivename($opt)) {
4240 vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}))
4241 if defined($conf->{$opt});
4242 $conf->{$opt} = $conf->{pending}->{$opt};
4244 $conf->{$opt} = $conf->{pending}->{$opt};
4247 delete $conf->{pending}->{$opt};
4248 PVE::QemuConfig->write_config($vmid, $conf);
4252 my $safe_num_ne = sub {
4255 return 0 if !defined($a) && !defined($b);
4256 return 1 if !defined($a);
4257 return 1 if !defined($b);
4262 my $safe_string_ne = sub {
4265 return 0 if !defined($a) && !defined($b);
4266 return 1 if !defined($a);
4267 return 1 if !defined($b);
4272 sub vmconfig_update_net {
4273 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value) = @_;
4275 my $newnet = parse_net($value);
4277 if ($conf->{$opt}) {
4278 my $oldnet = parse_net($conf->{$opt});
4280 if (&$safe_string_ne($oldnet->{model}, $newnet->{model}) ||
4281 &$safe_string_ne($oldnet->{macaddr}, $newnet->{macaddr}) ||
4282 &$safe_num_ne($oldnet->{queues}, $newnet->{queues}) ||
4283 !($newnet->{bridge} && $oldnet->{bridge})) { # bridge/nat mode change
4285 # for non online change, we try to hot-unplug
4286 die "skip
\n" if !$hotplug;
4287 vm_deviceunplug($vmid, $conf, $opt);
4290 die "internal error
" if $opt !~ m/net(\d+)/;
4291 my $iface = "tap
${vmid
}i
$1";
4293 if (&$safe_string_ne($oldnet->{bridge}, $newnet->{bridge}) ||
4294 &$safe_num_ne($oldnet->{tag}, $newnet->{tag}) ||
4295 &$safe_string_ne($oldnet->{trunks}, $newnet->{trunks}) ||
4296 &$safe_num_ne($oldnet->{firewall}, $newnet->{firewall})) {
4297 PVE::Network::tap_unplug($iface);
4298 PVE::Network::tap_plug($iface, $newnet->{bridge}, $newnet->{tag}, $newnet->{firewall}, $newnet->{trunks}, $newnet->{rate});
4299 } elsif (&$safe_num_ne($oldnet->{rate}, $newnet->{rate})) {
4300 # Rate can be applied on its own but any change above needs to
4301 # include the rate in tap_plug since OVS resets everything.
4302 PVE::Network::tap_rate_limit($iface, $newnet->{rate});
4305 if (&$safe_string_ne($oldnet->{link_down}, $newnet->{link_down})) {
4306 qemu_set_link_status($vmid, $opt, !$newnet->{link_down});
4314 vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet);
4320 sub vmconfig_update_disk {
4321 my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force) = @_;
4323 # fixme: do we need force?
4325 my $drive = parse_drive($opt, $value);
4327 if ($conf->{$opt}) {
4329 if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
4331 my $media = $drive->{media} || 'disk';
4332 my $oldmedia = $old_drive->{media} || 'disk';
4333 die "unable to change media type
\n" if $media ne $oldmedia;
4335 if (!drive_is_cdrom($old_drive)) {
4337 if ($drive->{file} ne $old_drive->{file}) {
4339 die "skip
\n" if !$hotplug;
4341 # unplug and register as unused
4342 vm_deviceunplug($vmid, $conf, $opt);
4343 vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
4346 # update existing disk
4348 # skip non hotpluggable value
4349 if (&$safe_num_ne($drive->{discard}, $old_drive->{discard}) ||
4350 &$safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
4351 &$safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
4352 &$safe_string_ne($drive->{cache}, $old_drive->{cache})) {
4357 if (&$safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
4358 &$safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
4359 &$safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
4360 &$safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
4361 &$safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
4362 &$safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
4363 &$safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
4364 &$safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
4365 &$safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
4366 &$safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
4367 &$safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
4368 &$safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max})) {
4370 qemu_block_set_io_throttle($vmid,"drive-
$opt",
4371 ($drive->{mbps} || 0)*1024*1024,
4372 ($drive->{mbps_rd} || 0)*1024*1024,
4373 ($drive->{mbps_wr} || 0)*1024*1024,
4374 $drive->{iops} || 0,
4375 $drive->{iops_rd} || 0,
4376 $drive->{iops_wr} || 0,
4377 ($drive->{mbps_max} || 0)*1024*1024,
4378 ($drive->{mbps_rd_max} || 0)*1024*1024,
4379 ($drive->{mbps_wr_max} || 0)*1024*1024,
4380 $drive->{iops_max} || 0,
4381 $drive->{iops_rd_max} || 0,
4382 $drive->{iops_wr_max} || 0);
4391 if ($drive->{file} eq 'none') {
4392 vm_mon_cmd($vmid, "eject
",force => JSON::true,device => "drive-
$opt");
4394 my $path = get_iso_path($storecfg, $vmid, $drive->{file});
4395 vm_mon_cmd($vmid, "eject
", force => JSON::true,device => "drive-
$opt"); # force eject if locked
4396 vm_mon_cmd($vmid, "change
", device => "drive-
$opt",target => "$path") if $path;
4404 die "skip
\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
4406 PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
4407 vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive);
4411 my ($storecfg, $vmid, $statefile, $skiplock, $migratedfrom, $paused,
4412 $forcemachine, $spice_ticket) = @_;
4414 PVE::QemuConfig->lock_config($vmid, sub {
4415 my $conf = PVE::QemuConfig->load_config($vmid, $migratedfrom);
4417 die "you can
't start a vm if it's a template
\n" if PVE::QemuConfig->is_template($conf);
4419 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4421 die "VM
$vmid already running
\n" if check_running($vmid, undef, $migratedfrom);
4423 if (!$statefile && scalar(keys %{$conf->{pending}})) {
4424 vmconfig_apply_pending($vmid, $conf, $storecfg);
4425 $conf = PVE::QemuConfig->load_config($vmid); # update/reload
4428 my $defaults = load_defaults();
4430 # set environment variable useful inside network script
4431 $ENV{PVE_MIGRATED_FROM} = $migratedfrom if $migratedfrom;
4433 my ($cmd, $vollist, $spice_port) = config_to_command($storecfg, $vmid, $conf, $defaults, $forcemachine);
4435 my $migrate_port = 0;
4438 if ($statefile eq 'tcp') {
4439 my $localip = "localhost
";
4440 my $datacenterconf = PVE::Cluster::cfs_read_file('datacenter.cfg');
4441 my $nodename = PVE::INotify::nodename();
4442 if ($datacenterconf->{migration_unsecure}) {
4443 $localip = PVE::Cluster::remote_node_ip($nodename, 1);
4444 $localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
4446 my $pfamily = PVE::Tools::get_host_address_family($nodename);
4447 $migrate_port = PVE::Tools::next_migrate_port($pfamily);
4448 $migrate_uri = "tcp
:${localip
}:${migrate_port
}";
4449 push @$cmd, '-incoming', $migrate_uri;
4452 push @$cmd, '-loadstate', $statefile;
4459 for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++) {
4460 my $d = parse_hostpci($conf->{"hostpci
$i"});
4462 my $pcidevices = $d->{pciid};
4463 foreach my $pcidevice (@$pcidevices) {
4464 my $pciid = $pcidevice->{id}.".".$pcidevice->{function};
4466 my $info = pci_device_info("0000:$pciid");
4467 die "IOMMU
not present
\n" if !check_iommu_support();
4468 die "no pci device info
for device
'$pciid'\n" if !$info;
4469 die "can
't unbind/bind pci group to vfio '$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
4470 die "can't
reset pci device
'$pciid'\n" if $info->{has_fl_reset} and !pci_dev_reset($info);
4474 PVE::Storage::activate_volumes($storecfg, $vollist);
4476 eval { run_command($cmd, timeout => $statefile ? undef : 30,
4480 # deactivate volumes if start fails
4481 eval { PVE::Storage::deactivate_volumes($storecfg, $vollist); };
4482 die "start failed
: $err";
4485 print "migration listens on
$migrate_uri\n" if $migrate_uri;
4487 if ($statefile && $statefile ne 'tcp') {
4488 eval { vm_mon_cmd_nocheck($vmid, "cont
"); };
4492 if ($migratedfrom) {
4495 set_migration_caps($vmid);
4500 print "spice listens on port
$spice_port\n";
4501 if ($spice_ticket) {
4502 vm_mon_cmd_nocheck($vmid, "set_password
", protocol => 'spice', password => $spice_ticket);
4503 vm_mon_cmd_nocheck($vmid, "expire_password
", protocol => 'spice', time => "+30");
4509 if (!$statefile && (!defined($conf->{balloon}) || $conf->{balloon})) {
4510 vm_mon_cmd_nocheck($vmid, "balloon
", value => $conf->{balloon}*1024*1024)
4511 if $conf->{balloon};
4514 foreach my $opt (keys %$conf) {
4515 next if $opt !~ m/^net\d+$/;
4516 my $nicconf = parse_net($conf->{$opt});
4517 qemu_set_link_status($vmid, $opt, 0) if $nicconf->{link_down};
4521 vm_mon_cmd_nocheck($vmid, 'qom-set',
4522 path => "machine
/peripheral/balloon0
",
4523 property => "guest-stats-polling-interval
",
4524 value => 2) if (!defined($conf->{balloon}) || $conf->{balloon});
4530 my ($vmid, $execute, %params) = @_;
4532 my $cmd = { execute => $execute, arguments => \%params };
4533 vm_qmp_command($vmid, $cmd);
4536 sub vm_mon_cmd_nocheck {
4537 my ($vmid, $execute, %params) = @_;
4539 my $cmd = { execute => $execute, arguments => \%params };
4540 vm_qmp_command($vmid, $cmd, 1);
4543 sub vm_qmp_command {
4544 my ($vmid, $cmd, $nocheck) = @_;
4549 if ($cmd->{arguments} && $cmd->{arguments}->{timeout}) {
4550 $timeout = $cmd->{arguments}->{timeout};
4551 delete $cmd->{arguments}->{timeout};
4555 die "VM
$vmid not running
\n" if !check_running($vmid, $nocheck);
4556 my $sname = qmp_socket($vmid);
4557 if (-e $sname) { # test if VM is reasonambe new and supports qmp/qga
4558 my $qmpclient = PVE::QMPClient->new();
4560 $res = $qmpclient->cmd($vmid, $cmd, $timeout);
4561 } elsif (-e "${var_run_tmpdir
}/$vmid.mon
") {
4562 die "can
't execute complex command on old monitor - stop/start your vm to fix the problem\n"
4563 if scalar(%{$cmd->{arguments}});
4564 vm_monitor_command($vmid, $cmd->{execute}, $nocheck);
4566 die "unable to open monitor socket\n";
4570 syslog("err", "VM $vmid qmp command failed - $err");
4577 sub vm_human_monitor_command {
4578 my ($vmid, $cmdline) = @_;
4583 execute => 'human-monitor-command
',
4584 arguments => { 'command-line
' => $cmdline},
4587 return vm_qmp_command($vmid, $cmd);
4590 sub vm_commandline {
4591 my ($storecfg, $vmid) = @_;
4593 my $conf = PVE::QemuConfig->load_config($vmid);
4595 my $defaults = load_defaults();
4597 my $cmd = config_to_command($storecfg, $vmid, $conf, $defaults);
4599 return join(' ', @$cmd);
4603 my ($vmid, $skiplock) = @_;
4605 PVE::QemuConfig->lock_config($vmid, sub {
4607 my $conf = PVE::QemuConfig->load_config($vmid);
4609 PVE::QemuConfig->check_lock($conf) if !$skiplock;
4611 vm_mon_cmd($vmid, "system_reset");
4615 sub get_vm_volumes {
4619 foreach_volid($conf, sub {
4620 my ($volid, $is_cdrom) = @_;
4622 return if $volid =~ m|^/|;
4624 my ($sid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
4627 push @$vollist, $volid;
4633 sub vm_stop_cleanup {
4634 my ($storecfg, $vmid, $conf, $keepActive, $apply_pending_changes) = @_;
4639 my $vollist = get_vm_volumes($conf);
4640 PVE::Storage::deactivate_volumes($storecfg, $vollist);
4643 foreach my $ext (qw(mon qmp pid vnc qga)) {
4644 unlink "/var/run/qemu-server/${vmid}.$ext";
4647 vmconfig_apply_pending
($vmid, $conf, $storecfg) if $apply_pending_changes;
4649 warn $@ if $@; # avoid errors - just warn
4652 # Note: use $nockeck to skip tests if VM configuration file exists.
4653 # We need that when migration VMs to other nodes (files already moved)
4654 # Note: we set $keepActive in vzdump stop mode - volumes need to stay active
4656 my ($storecfg, $vmid, $skiplock, $nocheck, $timeout, $shutdown, $force, $keepActive, $migratedfrom) = @_;
4658 $force = 1 if !defined($force) && !$shutdown;
4661 my $pid = check_running
($vmid, $nocheck, $migratedfrom);
4662 kill 15, $pid if $pid;
4663 my $conf = PVE
::QemuConfig-
>load_config($vmid, $migratedfrom);
4664 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 0);
4668 PVE
::QemuConfig-
>lock_config($vmid, sub {
4670 my $pid = check_running
($vmid, $nocheck);
4675 $conf = PVE
::QemuConfig-
>load_config($vmid);
4676 PVE
::QemuConfig-
>check_lock($conf) if !$skiplock;
4677 if (!defined($timeout) && $shutdown && $conf->{startup
}) {
4678 my $opts = PVE
::JSONSchema
::pve_parse_startup_order
($conf->{startup
});
4679 $timeout = $opts->{down
} if $opts->{down
};
4683 $timeout = 60 if !defined($timeout);
4687 if (defined($conf) && $conf->{agent
}) {
4688 vm_qmp_command
($vmid, { execute
=> "guest-shutdown" }, $nocheck);
4690 vm_qmp_command
($vmid, { execute
=> "system_powerdown" }, $nocheck);
4693 vm_qmp_command
($vmid, { execute
=> "quit" }, $nocheck);
4700 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
4705 if ($count >= $timeout) {
4707 warn "VM still running - terminating now with SIGTERM\n";
4710 die "VM quit/powerdown failed - got timeout\n";
4713 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
4718 warn "VM quit/powerdown failed - terminating now with SIGTERM\n";
4721 die "VM quit/powerdown failed\n";
4729 while (($count < $timeout) && check_running
($vmid, $nocheck)) {
4734 if ($count >= $timeout) {
4735 warn "VM still running - terminating now with SIGKILL\n";
4740 vm_stop_cleanup
($storecfg, $vmid, $conf, $keepActive, 1) if $conf;
4745 my ($vmid, $skiplock) = @_;
4747 PVE
::QemuConfig-
>lock_config($vmid, sub {
4749 my $conf = PVE
::QemuConfig-
>load_config($vmid);
4751 PVE
::QemuConfig-
>check_lock($conf)
4752 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
4754 vm_mon_cmd
($vmid, "stop");
4759 my ($vmid, $skiplock, $nocheck) = @_;
4761 PVE
::QemuConfig-
>lock_config($vmid, sub {
4765 my $conf = PVE
::QemuConfig-
>load_config($vmid);
4767 PVE
::QemuConfig-
>check_lock($conf)
4768 if !($skiplock || PVE
::QemuConfig-
>has_lock($conf, 'backup'));
4770 vm_mon_cmd
($vmid, "cont");
4773 vm_mon_cmd_nocheck
($vmid, "cont");
4779 my ($vmid, $skiplock, $key) = @_;
4781 PVE
::QemuConfig-
>lock_config($vmid, sub {
4783 my $conf = PVE
::QemuConfig-
>load_config($vmid);
4785 # there is no qmp command, so we use the human monitor command
4786 vm_human_monitor_command
($vmid, "sendkey $key");
4791 my ($storecfg, $vmid, $skiplock) = @_;
4793 PVE
::QemuConfig-
>lock_config($vmid, sub {
4795 my $conf = PVE
::QemuConfig-
>load_config($vmid);
4797 if (!check_running
($vmid)) {
4798 destroy_vm
($storecfg, $vmid, undef, $skiplock);
4800 die "VM $vmid is running - destroy failed\n";
4808 my ($filename, $buf) = @_;
4810 my $fh = IO
::File-
>new($filename, "w");
4811 return undef if !$fh;
4813 my $res = print $fh $buf;
4820 sub pci_device_info
{
4825 return undef if $name !~ m/^([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\.([a-f0-9])$/;
4826 my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4);
4828 my $irq = file_read_firstline
("$pcisysfs/devices/$name/irq");
4829 return undef if !defined($irq) || $irq !~ m/^\d+$/;
4831 my $vendor = file_read_firstline
("$pcisysfs/devices/$name/vendor");
4832 return undef if !defined($vendor) || $vendor !~ s/^0x//;
4834 my $product = file_read_firstline
("$pcisysfs/devices/$name/device");
4835 return undef if !defined($product) || $product !~ s/^0x//;
4840 product
=> $product,
4846 has_fl_reset
=> -f
"$pcisysfs/devices/$name/reset" || 0,
4855 my $name = $dev->{name
};
4857 my $fn = "$pcisysfs/devices/$name/reset";
4859 return file_write
($fn, "1");
4862 sub pci_dev_bind_to_vfio
{
4865 my $name = $dev->{name
};
4867 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
4869 if (!-d
$vfio_basedir) {
4870 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
4872 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
4874 my $testdir = "$vfio_basedir/$name";
4875 return 1 if -d
$testdir;
4877 my $data = "$dev->{vendor} $dev->{product}";
4878 return undef if !file_write
("$vfio_basedir/new_id", $data);
4880 my $fn = "$pcisysfs/devices/$name/driver/unbind";
4881 if (!file_write
($fn, $name)) {
4882 return undef if -f
$fn;
4885 $fn = "$vfio_basedir/bind";
4886 if (! -d
$testdir) {
4887 return undef if !file_write
($fn, $name);
4893 sub pci_dev_group_bind_to_vfio
{
4896 my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
4898 if (!-d
$vfio_basedir) {
4899 system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
4901 die "Cannot find vfio-pci module!\n" if !-d
$vfio_basedir;
4903 # get IOMMU group devices
4904 opendir(my $D, "$pcisysfs/devices/0000:$pciid/iommu_group/devices/") || die "Cannot open iommu_group: $!\n";
4905 my @devs = grep /^0000:/, readdir($D);
4908 foreach my $pciid (@devs) {
4909 $pciid =~ m/^([:\.\da-f]+)$/ or die "PCI ID $pciid not valid!\n";
4911 # pci bridges, switches or root ports are not supported
4912 # they have a pci_bus subdirectory so skip them
4913 next if (-e
"$pcisysfs/devices/$pciid/pci_bus");
4915 my $info = pci_device_info
($1);
4916 pci_dev_bind_to_vfio
($info) || die "Cannot bind $pciid to vfio\n";
4922 sub print_pci_addr
{
4923 my ($id, $bridges) = @_;
4927 piix3
=> { bus
=> 0, addr
=> 1 },
4928 #addr2 : first videocard
4929 balloon0
=> { bus
=> 0, addr
=> 3 },
4930 watchdog
=> { bus
=> 0, addr
=> 4 },
4931 scsihw0
=> { bus
=> 0, addr
=> 5 },
4932 'pci.3' => { bus
=> 0, addr
=> 5 }, #can also be used for virtio-scsi-single bridge
4933 scsihw1
=> { bus
=> 0, addr
=> 6 },
4934 ahci0
=> { bus
=> 0, addr
=> 7 },
4935 qga0
=> { bus
=> 0, addr
=> 8 },
4936 spice
=> { bus
=> 0, addr
=> 9 },
4937 virtio0
=> { bus
=> 0, addr
=> 10 },
4938 virtio1
=> { bus
=> 0, addr
=> 11 },
4939 virtio2
=> { bus
=> 0, addr
=> 12 },
4940 virtio3
=> { bus
=> 0, addr
=> 13 },
4941 virtio4
=> { bus
=> 0, addr
=> 14 },
4942 virtio5
=> { bus
=> 0, addr
=> 15 },
4943 hostpci0
=> { bus
=> 0, addr
=> 16 },
4944 hostpci1
=> { bus
=> 0, addr
=> 17 },
4945 net0
=> { bus
=> 0, addr
=> 18 },
4946 net1
=> { bus
=> 0, addr
=> 19 },
4947 net2
=> { bus
=> 0, addr
=> 20 },
4948 net3
=> { bus
=> 0, addr
=> 21 },
4949 net4
=> { bus
=> 0, addr
=> 22 },
4950 net5
=> { bus
=> 0, addr
=> 23 },
4951 vga1
=> { bus
=> 0, addr
=> 24 },
4952 vga2
=> { bus
=> 0, addr
=> 25 },
4953 vga3
=> { bus
=> 0, addr
=> 26 },
4954 hostpci2
=> { bus
=> 0, addr
=> 27 },
4955 hostpci3
=> { bus
=> 0, addr
=> 28 },
4956 #addr29 : usb-host (pve-usb.cfg)
4957 'pci.1' => { bus
=> 0, addr
=> 30 },
4958 'pci.2' => { bus
=> 0, addr
=> 31 },
4959 'net6' => { bus
=> 1, addr
=> 1 },
4960 'net7' => { bus
=> 1, addr
=> 2 },
4961 'net8' => { bus
=> 1, addr
=> 3 },
4962 'net9' => { bus
=> 1, addr
=> 4 },
4963 'net10' => { bus
=> 1, addr
=> 5 },
4964 'net11' => { bus
=> 1, addr
=> 6 },
4965 'net12' => { bus
=> 1, addr
=> 7 },
4966 'net13' => { bus
=> 1, addr
=> 8 },
4967 'net14' => { bus
=> 1, addr
=> 9 },
4968 'net15' => { bus
=> 1, addr
=> 10 },
4969 'net16' => { bus
=> 1, addr
=> 11 },
4970 'net17' => { bus
=> 1, addr
=> 12 },
4971 'net18' => { bus
=> 1, addr
=> 13 },
4972 'net19' => { bus
=> 1, addr
=> 14 },
4973 'net20' => { bus
=> 1, addr
=> 15 },
4974 'net21' => { bus
=> 1, addr
=> 16 },
4975 'net22' => { bus
=> 1, addr
=> 17 },
4976 'net23' => { bus
=> 1, addr
=> 18 },
4977 'net24' => { bus
=> 1, addr
=> 19 },
4978 'net25' => { bus
=> 1, addr
=> 20 },
4979 'net26' => { bus
=> 1, addr
=> 21 },
4980 'net27' => { bus
=> 1, addr
=> 22 },
4981 'net28' => { bus
=> 1, addr
=> 23 },
4982 'net29' => { bus
=> 1, addr
=> 24 },
4983 'net30' => { bus
=> 1, addr
=> 25 },
4984 'net31' => { bus
=> 1, addr
=> 26 },
4985 'xhci' => { bus
=> 1, addr
=> 27 },
4986 'virtio6' => { bus
=> 2, addr
=> 1 },
4987 'virtio7' => { bus
=> 2, addr
=> 2 },
4988 'virtio8' => { bus
=> 2, addr
=> 3 },
4989 'virtio9' => { bus
=> 2, addr
=> 4 },
4990 'virtio10' => { bus
=> 2, addr
=> 5 },
4991 'virtio11' => { bus
=> 2, addr
=> 6 },
4992 'virtio12' => { bus
=> 2, addr
=> 7 },
4993 'virtio13' => { bus
=> 2, addr
=> 8 },
4994 'virtio14' => { bus
=> 2, addr
=> 9 },
4995 'virtio15' => { bus
=> 2, addr
=> 10 },
4996 'virtioscsi0' => { bus
=> 3, addr
=> 1 },
4997 'virtioscsi1' => { bus
=> 3, addr
=> 2 },
4998 'virtioscsi2' => { bus
=> 3, addr
=> 3 },
4999 'virtioscsi3' => { bus
=> 3, addr
=> 4 },
5000 'virtioscsi4' => { bus
=> 3, addr
=> 5 },
5001 'virtioscsi5' => { bus
=> 3, addr
=> 6 },
5002 'virtioscsi6' => { bus
=> 3, addr
=> 7 },
5003 'virtioscsi7' => { bus
=> 3, addr
=> 8 },
5004 'virtioscsi8' => { bus
=> 3, addr
=> 9 },
5005 'virtioscsi9' => { bus
=> 3, addr
=> 10 },
5006 'virtioscsi10' => { bus
=> 3, addr
=> 11 },
5007 'virtioscsi11' => { bus
=> 3, addr
=> 12 },
5008 'virtioscsi12' => { bus
=> 3, addr
=> 13 },
5009 'virtioscsi13' => { bus
=> 3, addr
=> 14 },
5010 'virtioscsi14' => { bus
=> 3, addr
=> 15 },
5011 'virtioscsi15' => { bus
=> 3, addr
=> 16 },
5012 'virtioscsi16' => { bus
=> 3, addr
=> 17 },
5013 'virtioscsi17' => { bus
=> 3, addr
=> 18 },
5014 'virtioscsi18' => { bus
=> 3, addr
=> 19 },
5015 'virtioscsi19' => { bus
=> 3, addr
=> 20 },
5016 'virtioscsi20' => { bus
=> 3, addr
=> 21 },
5017 'virtioscsi21' => { bus
=> 3, addr
=> 22 },
5018 'virtioscsi22' => { bus
=> 3, addr
=> 23 },
5019 'virtioscsi23' => { bus
=> 3, addr
=> 24 },
5020 'virtioscsi24' => { bus
=> 3, addr
=> 25 },
5021 'virtioscsi25' => { bus
=> 3, addr
=> 26 },
5022 'virtioscsi26' => { bus
=> 3, addr
=> 27 },
5023 'virtioscsi27' => { bus
=> 3, addr
=> 28 },
5024 'virtioscsi28' => { bus
=> 3, addr
=> 29 },
5025 'virtioscsi29' => { bus
=> 3, addr
=> 30 },
5026 'virtioscsi30' => { bus
=> 3, addr
=> 31 },
5030 if (defined($devices->{$id}->{bus
}) && defined($devices->{$id}->{addr
})) {
5031 my $addr = sprintf("0x%x", $devices->{$id}->{addr
});
5032 my $bus = $devices->{$id}->{bus
};
5033 $res = ",bus=pci.$bus,addr=$addr";
5034 $bridges->{$bus} = 1 if $bridges;
5040 sub print_pcie_addr
{
5045 hostpci0
=> { bus
=> "ich9-pcie-port-1", addr
=> 0 },
5046 hostpci1
=> { bus
=> "ich9-pcie-port-2", addr
=> 0 },
5047 hostpci2
=> { bus
=> "ich9-pcie-port-3", addr
=> 0 },
5048 hostpci3
=> { bus
=> "ich9-pcie-port-4", addr
=> 0 },
5051 if (defined($devices->{$id}->{bus
}) && defined($devices->{$id}->{addr
})) {
5052 my $addr = sprintf("0x%x", $devices->{$id}->{addr
});
5053 my $bus = $devices->{$id}->{bus
};
5054 $res = ",bus=$bus,addr=$addr";
5060 # vzdump restore implementaion
5062 sub tar_archive_read_firstfile
{
5063 my $archive = shift;
5065 die "ERROR: file '$archive' does not exist\n" if ! -f
$archive;
5067 # try to detect archive type first
5068 my $pid = open (TMP
, "tar tf '$archive'|") ||
5069 die "unable to open file '$archive'\n";
5070 my $firstfile = <TMP
>;
5074 die "ERROR: archive contaions no data\n" if !$firstfile;
5080 sub tar_restore_cleanup
{
5081 my ($storecfg, $statfile) = @_;
5083 print STDERR
"starting cleanup\n";
5085 if (my $fd = IO
::File-
>new($statfile, "r")) {
5086 while (defined(my $line = <$fd>)) {
5087 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5090 if ($volid =~ m
|^/|) {
5091 unlink $volid || die 'unlink failed\n';
5093 PVE
::Storage
::vdisk_free
($storecfg, $volid);
5095 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5097 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5099 print STDERR
"unable to parse line in statfile - $line";
5106 sub restore_archive
{
5107 my ($archive, $vmid, $user, $opts) = @_;
5109 my $format = $opts->{format
};
5112 if ($archive =~ m/\.tgz$/ || $archive =~ m/\.tar\.gz$/) {
5113 $format = 'tar' if !$format;
5115 } elsif ($archive =~ m/\.tar$/) {
5116 $format = 'tar' if !$format;
5117 } elsif ($archive =~ m/.tar.lzo$/) {
5118 $format = 'tar' if !$format;
5120 } elsif ($archive =~ m/\.vma$/) {
5121 $format = 'vma' if !$format;
5122 } elsif ($archive =~ m/\.vma\.gz$/) {
5123 $format = 'vma' if !$format;
5125 } elsif ($archive =~ m/\.vma\.lzo$/) {
5126 $format = 'vma' if !$format;
5129 $format = 'vma' if !$format; # default
5132 # try to detect archive format
5133 if ($format eq 'tar') {
5134 return restore_tar_archive
($archive, $vmid, $user, $opts);
5136 return restore_vma_archive
($archive, $vmid, $user, $opts, $comp);
5140 sub restore_update_config_line
{
5141 my ($outfd, $cookie, $vmid, $map, $line, $unique) = @_;
5143 return if $line =~ m/^\#qmdump\#/;
5144 return if $line =~ m/^\#vzdump\#/;
5145 return if $line =~ m/^lock:/;
5146 return if $line =~ m/^unused\d+:/;
5147 return if $line =~ m/^parent:/;
5148 return if $line =~ m/^template:/; # restored VM is never a template
5150 if (($line =~ m/^(vlan(\d+)):\s*(\S+)\s*$/)) {
5151 # try to convert old 1.X settings
5152 my ($id, $ind, $ethcfg) = ($1, $2, $3);
5153 foreach my $devconfig (PVE
::Tools
::split_list
($ethcfg)) {
5154 my ($model, $macaddr) = split(/\=/, $devconfig);
5155 $macaddr = PVE
::Tools
::random_ether_addr
() if !$macaddr || $unique;
5158 bridge
=> "vmbr$ind",
5159 macaddr
=> $macaddr,
5161 my $netstr = print_net
($net);
5163 print $outfd "net$cookie->{netcount}: $netstr\n";
5164 $cookie->{netcount
}++;
5166 } elsif (($line =~ m/^(net\d+):\s*(\S+)\s*$/) && $unique) {
5167 my ($id, $netstr) = ($1, $2);
5168 my $net = parse_net
($netstr);
5169 $net->{macaddr
} = PVE
::Tools
::random_ether_addr
() if $net->{macaddr
};
5170 $netstr = print_net
($net);
5171 print $outfd "$id: $netstr\n";
5172 } elsif ($line =~ m/^((ide|scsi|virtio|sata)\d+):\s*(\S+)\s*$/) {
5175 my $di = parse_drive
($virtdev, $value);
5176 if (defined($di->{backup
}) && !$di->{backup
}) {
5177 print $outfd "#$line";
5178 } elsif ($map->{$virtdev}) {
5179 delete $di->{format
}; # format can change on restore
5180 $di->{file
} = $map->{$virtdev};
5181 $value = print_drive
($vmid, $di);
5182 print $outfd "$virtdev: $value\n";
5192 my ($cfg, $vmid) = @_;
5194 my $info = PVE
::Storage
::vdisk_list
($cfg, undef, $vmid);
5196 my $volid_hash = {};
5197 foreach my $storeid (keys %$info) {
5198 foreach my $item (@{$info->{$storeid}}) {
5199 next if !($item->{volid
} && $item->{size
});
5200 $item->{path
} = PVE
::Storage
::path
($cfg, $item->{volid
});
5201 $volid_hash->{$item->{volid
}} = $item;
5208 sub is_volume_in_use
{
5209 my ($storecfg, $conf, $skip_drive, $volid) = @_;
5211 my $path = PVE
::Storage
::path
($storecfg, $volid);
5213 my $scan_config = sub {
5214 my ($cref, $snapname) = @_;
5216 foreach my $key (keys %$cref) {
5217 my $value = $cref->{$key};
5218 if (is_valid_drivename
($key)) {
5219 next if $skip_drive && $key eq $skip_drive;
5220 my $drive = parse_drive
($key, $value);
5221 next if !$drive || !$drive->{file
} || drive_is_cdrom
($drive);
5222 return 1 if $volid eq $drive->{file
};
5223 if ($drive->{file
} =~ m!^/!) {
5224 return 1 if $drive->{file
} eq $path;
5226 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
}, 1);
5228 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid, 1);
5230 return 1 if $path eq PVE
::Storage
::path
($storecfg, $drive->{file
}, $snapname);
5238 return 1 if &$scan_config($conf);
5242 foreach my $snapname (keys %{$conf->{snapshots
}}) {
5243 return 1 if &$scan_config($conf->{snapshots
}->{$snapname}, $snapname);
5249 sub update_disksize
{
5250 my ($vmid, $conf, $volid_hash) = @_;
5256 # Note: it is allowed to define multiple storages with same path (alias), so
5257 # we need to check both 'volid' and real 'path' (two different volid can point
5258 # to the same path).
5263 foreach my $opt (keys %$conf) {
5264 if (is_valid_drivename
($opt)) {
5265 my $drive = parse_drive
($opt, $conf->{$opt});
5266 my $volid = $drive->{file
};
5269 $used->{$volid} = 1;
5270 if ($volid_hash->{$volid} &&
5271 (my $path = $volid_hash->{$volid}->{path
})) {
5272 $usedpath->{$path} = 1;
5275 next if drive_is_cdrom
($drive);
5276 next if !$volid_hash->{$volid};
5278 $drive->{size
} = $volid_hash->{$volid}->{size
};
5279 my $new = print_drive
($vmid, $drive);
5280 if ($new ne $conf->{$opt}) {
5282 $conf->{$opt} = $new;
5287 # remove 'unusedX' entry if volume is used
5288 foreach my $opt (keys %$conf) {
5289 next if $opt !~ m/^unused\d+$/;
5290 my $volid = $conf->{$opt};
5291 my $path = $volid_hash->{$volid}->{path
} if $volid_hash->{$volid};
5292 if ($used->{$volid} || ($path && $usedpath->{$path})) {
5294 delete $conf->{$opt};
5298 foreach my $volid (sort keys %$volid_hash) {
5299 next if $volid =~ m/vm-$vmid-state-/;
5300 next if $used->{$volid};
5301 my $path = $volid_hash->{$volid}->{path
};
5302 next if !$path; # just to be sure
5303 next if $usedpath->{$path};
5305 PVE
::QemuConfig-
>add_unused_volume($conf, $volid);
5306 $usedpath->{$path} = 1; # avoid to add more than once (aliases)
5313 my ($vmid, $nolock) = @_;
5315 my $cfg = PVE
::Cluster
::cfs_read_file
("storage.cfg");
5317 my $volid_hash = scan_volids
($cfg, $vmid);
5319 my $updatefn = sub {
5322 my $conf = PVE
::QemuConfig-
>load_config($vmid);
5324 PVE
::QemuConfig-
>check_lock($conf);
5327 foreach my $volid (keys %$volid_hash) {
5328 my $info = $volid_hash->{$volid};
5329 $vm_volids->{$volid} = $info if $info->{vmid
} && $info->{vmid
} == $vmid;
5332 my $changes = update_disksize
($vmid, $conf, $vm_volids);
5334 PVE
::QemuConfig-
>write_config($vmid, $conf) if $changes;
5337 if (defined($vmid)) {
5341 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5344 my $vmlist = config_list
();
5345 foreach my $vmid (keys %$vmlist) {
5349 PVE
::QemuConfig-
>lock_config($vmid, $updatefn, $vmid);
5355 sub restore_vma_archive
{
5356 my ($archive, $vmid, $user, $opts, $comp) = @_;
5358 my $input = $archive eq '-' ?
"<&STDIN" : undef;
5359 my $readfrom = $archive;
5364 my $qarchive = PVE
::Tools
::shellquote
($archive);
5365 if ($comp eq 'gzip') {
5366 $uncomp = "zcat $qarchive|";
5367 } elsif ($comp eq 'lzop') {
5368 $uncomp = "lzop -d -c $qarchive|";
5370 die "unknown compression method '$comp'\n";
5375 my $tmpdir = "/var/tmp/vzdumptmp$$";
5378 # disable interrupts (always do cleanups)
5379 local $SIG{INT
} = $SIG{TERM
} = $SIG{QUIT
} = $SIG{HUP
} = sub {
5380 warn "got interrupt - ignored\n";
5383 my $mapfifo = "/var/tmp/vzdumptmp$$.fifo";
5384 POSIX
::mkfifo
($mapfifo, 0600);
5387 my $openfifo = sub {
5388 open($fifofh, '>', $mapfifo) || die $!;
5391 my $cmd = "${uncomp}vma extract -v -r $mapfifo $readfrom $tmpdir";
5398 my $rpcenv = PVE
::RPCEnvironment
::get
();
5400 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5401 my $tmpfn = "$conffile.$$.tmp";
5403 # Note: $oldconf is undef if VM does not exists
5404 my $cfs_path = PVE
::QemuConfig-
>cfs_config_path($vmid);
5405 my $oldconf = PVE
::Cluster
::cfs_read_file
($cfs_path);
5407 my $print_devmap = sub {
5408 my $virtdev_hash = {};
5410 my $cfgfn = "$tmpdir/qemu-server.conf";
5412 # we can read the config - that is already extracted
5413 my $fh = IO
::File-
>new($cfgfn, "r") ||
5414 "unable to read qemu-server.conf - $!\n";
5416 my $fwcfgfn = "$tmpdir/qemu-server.fw";
5418 my $pve_firewall_dir = '/etc/pve/firewall';
5419 mkdir $pve_firewall_dir; # make sure the dir exists
5420 PVE
::Tools
::file_copy
($fwcfgfn, "${pve_firewall_dir}/$vmid.fw");
5423 while (defined(my $line = <$fh>)) {
5424 if ($line =~ m/^\#qmdump\#map:(\S+):(\S+):(\S*):(\S*):$/) {
5425 my ($virtdev, $devname, $storeid, $format) = ($1, $2, $3, $4);
5426 die "archive does not contain data for drive '$virtdev'\n"
5427 if !$devinfo->{$devname};
5428 if (defined($opts->{storage
})) {
5429 $storeid = $opts->{storage
} || 'local';
5430 } elsif (!$storeid) {
5433 $format = 'raw' if !$format;
5434 $devinfo->{$devname}->{devname
} = $devname;
5435 $devinfo->{$devname}->{virtdev
} = $virtdev;
5436 $devinfo->{$devname}->{format
} = $format;
5437 $devinfo->{$devname}->{storeid
} = $storeid;
5439 # check permission on storage
5440 my $pool = $opts->{pool
}; # todo: do we need that?
5441 if ($user ne 'root@pam') {
5442 $rpcenv->check($user, "/storage/$storeid", ['Datastore.AllocateSpace']);
5445 $virtdev_hash->{$virtdev} = $devinfo->{$devname};
5449 foreach my $devname (keys %$devinfo) {
5450 die "found no device mapping information for device '$devname'\n"
5451 if !$devinfo->{$devname}->{virtdev
};
5454 my $cfg = cfs_read_file
('storage.cfg');
5456 # create empty/temp config
5458 PVE
::Tools
::file_set_contents
($conffile, "memory: 128\n");
5459 foreach_drive
($oldconf, sub {
5460 my ($ds, $drive) = @_;
5462 return if drive_is_cdrom
($drive);
5464 my $volid = $drive->{file
};
5466 return if !$volid || $volid =~ m
|^/|;
5468 my ($path, $owner) = PVE
::Storage
::path
($cfg, $volid);
5469 return if !$path || !$owner || ($owner != $vmid);
5471 # Note: only delete disk we want to restore
5472 # other volumes will become unused
5473 if ($virtdev_hash->{$ds}) {
5474 PVE
::Storage
::vdisk_free
($cfg, $volid);
5478 # delete vmstate files
5479 # since after the restore we have no snapshots anymore
5480 foreach my $snapname (keys %{$oldconf->{snapshots
}}) {
5481 my $snap = $oldconf->{snapshots
}->{$snapname};
5482 if ($snap->{vmstate
}) {
5483 eval { PVE
::Storage
::vdisk_free
($cfg, $snap->{vmstate
}); };
5492 foreach my $virtdev (sort keys %$virtdev_hash) {
5493 my $d = $virtdev_hash->{$virtdev};
5494 my $alloc_size = int(($d->{size
} + 1024 - 1)/1024);
5495 my $scfg = PVE
::Storage
::storage_config
($cfg, $d->{storeid
});
5497 # test if requested format is supported
5498 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($cfg, $d->{storeid
});
5499 my $supported = grep { $_ eq $d->{format
} } @$validFormats;
5500 $d->{format
} = $defFormat if !$supported;
5502 my $volid = PVE
::Storage
::vdisk_alloc
($cfg, $d->{storeid
}, $vmid,
5503 $d->{format
}, undef, $alloc_size);
5504 print STDERR
"new volume ID is '$volid'\n";
5505 $d->{volid
} = $volid;
5506 my $path = PVE
::Storage
::path
($cfg, $volid);
5508 PVE
::Storage
::activate_volumes
($cfg,[$volid]);
5510 my $write_zeros = 1;
5511 if (PVE
::Storage
::volume_has_feature
($cfg, 'sparseinit', $volid)) {
5515 print $fifofh "${write_zeros}:$d->{devname}=$path\n";
5517 print "map '$d->{devname}' to '$path' (write zeros = ${write_zeros})\n";
5518 $map->{$virtdev} = $volid;
5521 $fh->seek(0, 0) || die "seek failed - $!\n";
5523 my $outfd = new IO
::File
($tmpfn, "w") ||
5524 die "unable to write config for VM $vmid\n";
5526 my $cookie = { netcount
=> 0 };
5527 while (defined(my $line = <$fh>)) {
5528 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
5537 local $SIG{INT
} = $SIG{TERM
} = $SIG{QUIT
} = $SIG{HUP
} = $SIG{PIPE
} = sub {
5538 die "interrupted by signal\n";
5540 local $SIG{ALRM
} = sub { die "got timeout\n"; };
5542 $oldtimeout = alarm($timeout);
5549 if ($line =~ m/^DEV:\sdev_id=(\d+)\ssize:\s(\d+)\sdevname:\s(\S+)$/) {
5550 my ($dev_id, $size, $devname) = ($1, $2, $3);
5551 $devinfo->{$devname} = { size
=> $size, dev_id
=> $dev_id };
5552 } elsif ($line =~ m/^CTIME: /) {
5553 # we correctly received the vma config, so we can disable
5554 # the timeout now for disk allocation (set to 10 minutes, so
5555 # that we always timeout if something goes wrong)
5558 print $fifofh "done\n";
5559 my $tmp = $oldtimeout || 0;
5560 $oldtimeout = undef;
5566 print "restore vma archive: $cmd\n";
5567 run_command
($cmd, input
=> $input, outfunc
=> $parser, afterfork
=> $openfifo);
5571 alarm($oldtimeout) if $oldtimeout;
5574 foreach my $devname (keys %$devinfo) {
5575 my $volid = $devinfo->{$devname}->{volid
};
5576 push @$vollist, $volid if $volid;
5579 my $cfg = cfs_read_file
('storage.cfg');
5580 PVE
::Storage
::deactivate_volumes
($cfg, $vollist);
5588 foreach my $devname (keys %$devinfo) {
5589 my $volid = $devinfo->{$devname}->{volid
};
5592 if ($volid =~ m
|^/|) {
5593 unlink $volid || die 'unlink failed\n';
5595 PVE
::Storage
::vdisk_free
($cfg, $volid);
5597 print STDERR
"temporary volume '$volid' sucessfuly removed\n";
5599 print STDERR
"unable to cleanup '$volid' - $@" if $@;
5606 rename($tmpfn, $conffile) ||
5607 die "unable to commit configuration file '$conffile'\n";
5609 PVE
::Cluster
::cfs_update
(); # make sure we read new file
5611 eval { rescan
($vmid, 1); };
5615 sub restore_tar_archive
{
5616 my ($archive, $vmid, $user, $opts) = @_;
5618 if ($archive ne '-') {
5619 my $firstfile = tar_archive_read_firstfile
($archive);
5620 die "ERROR: file '$archive' dos not lock like a QemuServer vzdump backup\n"
5621 if $firstfile ne 'qemu-server.conf';
5624 my $storecfg = cfs_read_file
('storage.cfg');
5626 # destroy existing data - keep empty config
5627 my $vmcfgfn = PVE
::QemuConfig-
>config_file($vmid);
5628 destroy_vm
($storecfg, $vmid, 1) if -f
$vmcfgfn;
5630 my $tocmd = "/usr/lib/qemu-server/qmextract";
5632 $tocmd .= " --storage " . PVE
::Tools
::shellquote
($opts->{storage
}) if $opts->{storage
};
5633 $tocmd .= " --pool " . PVE
::Tools
::shellquote
($opts->{pool
}) if $opts->{pool
};
5634 $tocmd .= ' --prealloc' if $opts->{prealloc
};
5635 $tocmd .= ' --info' if $opts->{info
};
5637 # tar option "xf" does not autodetect compression when read from STDIN,
5638 # so we pipe to zcat
5639 my $cmd = "zcat -f|tar xf " . PVE
::Tools
::shellquote
($archive) . " " .
5640 PVE
::Tools
::shellquote
("--to-command=$tocmd");
5642 my $tmpdir = "/var/tmp/vzdumptmp$$";
5645 local $ENV{VZDUMP_TMPDIR
} = $tmpdir;
5646 local $ENV{VZDUMP_VMID
} = $vmid;
5647 local $ENV{VZDUMP_USER
} = $user;
5649 my $conffile = PVE
::QemuConfig-
>config_file($vmid);
5650 my $tmpfn = "$conffile.$$.tmp";
5652 # disable interrupts (always do cleanups)
5653 local $SIG{INT
} = $SIG{TERM
} = $SIG{QUIT
} = $SIG{HUP
} = sub {
5654 print STDERR
"got interrupt - ignored\n";
5659 local $SIG{INT
} = $SIG{TERM
} = $SIG{QUIT
} = $SIG{HUP
} = $SIG{PIPE
} = sub {
5660 die "interrupted by signal\n";
5663 if ($archive eq '-') {
5664 print "extracting archive from STDIN\n";
5665 run_command
($cmd, input
=> "<&STDIN");
5667 print "extracting archive '$archive'\n";
5671 return if $opts->{info
};
5675 my $statfile = "$tmpdir/qmrestore.stat";
5676 if (my $fd = IO
::File-
>new($statfile, "r")) {
5677 while (defined (my $line = <$fd>)) {
5678 if ($line =~ m/vzdump:([^\s:]*):(\S+)$/) {
5679 $map->{$1} = $2 if $1;
5681 print STDERR
"unable to parse line in statfile - $line\n";
5687 my $confsrc = "$tmpdir/qemu-server.conf";
5689 my $srcfd = new IO
::File
($confsrc, "r") ||
5690 die "unable to open file '$confsrc'\n";
5692 my $outfd = new IO
::File
($tmpfn, "w") ||
5693 die "unable to write config for VM $vmid\n";
5695 my $cookie = { netcount
=> 0 };
5696 while (defined (my $line = <$srcfd>)) {
5697 restore_update_config_line
($outfd, $cookie, $vmid, $map, $line, $opts->{unique
});
5709 tar_restore_cleanup
($storecfg, "$tmpdir/qmrestore.stat") if !$opts->{info
};
5716 rename $tmpfn, $conffile ||
5717 die "unable to commit configuration file '$conffile'\n";
5719 PVE
::Cluster
::cfs_update
(); # make sure we read new file
5721 eval { rescan
($vmid, 1); };
5725 sub foreach_writable_storage
{
5726 my ($conf, $func) = @_;
5730 foreach my $ds (keys %$conf) {
5731 next if !is_valid_drivename
($ds);
5733 my $drive = parse_drive
($ds, $conf->{$ds});
5735 next if drive_is_cdrom
($drive);
5737 my $volid = $drive->{file
};
5739 my ($sid, $volname) = PVE
::Storage
::parse_volume_id
($volid, 1);
5740 $sidhash->{$sid} = $sid if $sid;
5743 foreach my $sid (sort keys %$sidhash) {
5748 sub do_snapshots_with_qemu
{
5749 my ($storecfg, $volid) = @_;
5751 my $storage_name = PVE
::Storage
::parse_volume_id
($volid);
5753 if ($qemu_snap_storage->{$storecfg->{ids
}->{$storage_name}->{type
}}
5754 && !$storecfg->{ids
}->{$storage_name}->{krbd
}){
5758 if ($volid =~ m/\.(qcow2|qed)$/){
5765 sub qga_check_running
{
5768 eval { vm_mon_cmd
($vmid, "guest-ping", timeout
=> 3); };
5770 warn "Qemu Guest Agent are not running - $@";
5776 sub template_create
{
5777 my ($vmid, $conf, $disk) = @_;
5779 my $storecfg = PVE
::Storage
::config
();
5781 foreach_drive
($conf, sub {
5782 my ($ds, $drive) = @_;
5784 return if drive_is_cdrom
($drive);
5785 return if $disk && $ds ne $disk;
5787 my $volid = $drive->{file
};
5788 return if !PVE
::Storage
::volume_has_feature
($storecfg, 'template', $volid);
5790 my $voliddst = PVE
::Storage
::vdisk_create_base
($storecfg, $volid);
5791 $drive->{file
} = $voliddst;
5792 $conf->{$ds} = print_drive
($vmid, $drive);
5793 PVE
::QemuConfig-
>write_config($vmid, $conf);
5797 sub qemu_img_convert
{
5798 my ($src_volid, $dst_volid, $size, $snapname) = @_;
5800 my $storecfg = PVE
::Storage
::config
();
5801 my ($src_storeid, $src_volname) = PVE
::Storage
::parse_volume_id
($src_volid, 1);
5802 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid, 1);
5804 if ($src_storeid && $dst_storeid) {
5806 PVE
::Storage
::activate_volumes
($storecfg, [$src_volid], $snapname);
5808 my $src_scfg = PVE
::Storage
::storage_config
($storecfg, $src_storeid);
5809 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
5811 my $src_format = qemu_img_format
($src_scfg, $src_volname);
5812 my $dst_format = qemu_img_format
($dst_scfg, $dst_volname);
5814 my $src_path = PVE
::Storage
::path
($storecfg, $src_volid, $snapname);
5815 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
5818 push @$cmd, '/usr/bin/qemu-img', 'convert', '-t', 'writeback', '-p', '-n';
5819 push @$cmd, '-s', $snapname if($snapname && $src_format eq "qcow2");
5820 push @$cmd, '-f', $src_format, '-O', $dst_format, $src_path, $dst_path;
5824 if($line =~ m/\((\S+)\/100\
%\)/){
5826 my $transferred = int($size * $percent / 100);
5827 my $remaining = $size - $transferred;
5829 print "transferred: $transferred bytes remaining: $remaining bytes total: $size bytes progression: $percent %\n";
5834 eval { run_command
($cmd, timeout
=> undef, outfunc
=> $parser); };
5836 die "copy failed: $err" if $err;
5840 sub qemu_img_format
{
5841 my ($scfg, $volname) = @_;
5843 if ($scfg->{path
} && $volname =~ m/\.(raw|cow|qcow|qcow2|qed|vmdk|cloop)$/) {
5850 sub qemu_drive_mirror
{
5851 my ($vmid, $drive, $dst_volid, $vmiddst) = @_;
5853 my $storecfg = PVE
::Storage
::config
();
5854 my ($dst_storeid, $dst_volname) = PVE
::Storage
::parse_volume_id
($dst_volid);
5856 my $dst_scfg = PVE
::Storage
::storage_config
($storecfg, $dst_storeid);
5858 my $format = qemu_img_format
($dst_scfg, $dst_volname);
5860 my $dst_path = PVE
::Storage
::path
($storecfg, $dst_volid);
5862 my $opts = { timeout
=> 10, device
=> "drive-$drive", mode
=> "existing", sync
=> "full", target
=> $dst_path };
5863 $opts->{format
} = $format if $format;
5865 print "drive mirror is starting (scanning bitmap) : this step can take some minutes/hours, depend of disk size and storage speed\n";
5868 vm_mon_cmd
($vmid, "drive-mirror", %$opts);
5870 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
5871 my $stat = @$stats[0];
5872 die "mirroring job seem to have die. Maybe do you have bad sectors?" if !$stat;
5873 die "error job is not mirroring" if $stat->{type
} ne "mirror";
5875 my $busy = $stat->{busy
};
5876 my $ready = $stat->{ready
};
5878 if (my $total = $stat->{len
}) {
5879 my $transferred = $stat->{offset
} || 0;
5880 my $remaining = $total - $transferred;
5881 my $percent = sprintf "%.2f", ($transferred * 100 / $total);
5883 print "transferred: $transferred bytes remaining: $remaining bytes total: $total bytes progression: $percent % busy: $busy ready: $ready \n";
5887 if ($stat->{ready
} eq 'true') {
5889 last if $vmiddst != $vmid;
5891 # try to switch the disk if source and destination are on the same guest
5892 eval { vm_mon_cmd
($vmid, "block-job-complete", device
=> "drive-$drive") };
5894 die $@ if $@ !~ m/cannot be completed/;
5903 my $cancel_job = sub {
5904 vm_mon_cmd
($vmid, "block-job-cancel", device
=> "drive-$drive");
5906 my $stats = vm_mon_cmd
($vmid, "query-block-jobs");
5907 my $stat = @$stats[0];
5914 eval { &$cancel_job(); };
5915 die "mirroring error: $err";
5918 if ($vmiddst != $vmid) {
5919 # if we clone a disk for a new target vm, we don't switch the disk
5920 &$cancel_job(); # so we call block-job-cancel
5925 my ($storecfg, $vmid, $running, $drivename, $drive, $snapname,
5926 $newvmid, $storage, $format, $full, $newvollist) = @_;
5931 print "create linked clone of drive $drivename ($drive->{file})\n";
5932 $newvolid = PVE
::Storage
::vdisk_clone
($storecfg, $drive->{file
}, $newvmid, $snapname);
5933 push @$newvollist, $newvolid;
5935 my ($storeid, $volname) = PVE
::Storage
::parse_volume_id
($drive->{file
});
5936 $storeid = $storage if $storage;
5938 my ($defFormat, $validFormats) = PVE
::Storage
::storage_default_format
($storecfg, $storeid);
5940 my $scfg = PVE
::Storage
::storage_config
($storecfg, $storeid);
5941 $format = qemu_img_format
($scfg, $volname);
5944 # test if requested format is supported - else use default
5945 my $supported = grep { $_ eq $format } @$validFormats;
5946 $format = $defFormat if !$supported;
5948 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $drive->{file
}, 3);
5950 print "create full clone of drive $drivename ($drive->{file})\n";
5951 $newvolid = PVE
::Storage
::vdisk_alloc
($storecfg, $storeid, $newvmid, $format, undef, ($size/1024));
5952 push @$newvollist, $newvolid;
5954 PVE
::Storage
::activate_volumes
($storecfg, $newvollist);
5956 if (!$running || $snapname) {
5957 qemu_img_convert
($drive->{file
}, $newvolid, $size, $snapname);
5959 qemu_drive_mirror
($vmid, $drivename, $newvolid, $newvmid);
5963 my ($size) = PVE
::Storage
::volume_size_info
($storecfg, $newvolid, 3);
5966 $disk->{format
} = undef;
5967 $disk->{file
} = $newvolid;
5968 $disk->{size
} = $size;
5973 # this only works if VM is running
5974 sub get_current_qemu_machine
{
5977 my $cmd = { execute
=> 'query-machines', arguments
=> {} };
5978 my $res = vm_qmp_command
($vmid, $cmd);
5980 my ($current, $default);
5981 foreach my $e (@$res) {
5982 $default = $e->{name
} if $e->{'is-default'};
5983 $current = $e->{name
} if $e->{'is-current'};
5986 # fallback to the default machine if current is not supported by qemu
5987 return $current || $default || 'pc';
5990 sub qemu_machine_feature_enabled
{
5991 my ($machine, $kvmver, $version_major, $version_minor) = @_;
5996 if ($machine && $machine =~ m/^(pc(-i440fx|-q35)?-(\d+)\.(\d+))/) {
5998 $current_major = $3;
5999 $current_minor = $4;
6001 } elsif ($kvmver =~ m/^(\d+)\.(\d+)/) {
6003 $current_major = $1;
6004 $current_minor = $2;
6007 return 1 if $current_major >= $version_major && $current_minor >= $version_minor;
6012 sub qemu_machine_pxe
{
6013 my ($vmid, $conf, $machine) = @_;
6015 $machine = PVE
::QemuServer
::get_current_qemu_machine
($vmid) if !$machine;
6017 foreach my $opt (keys %$conf) {
6018 next if $opt !~ m/^net(\d+)$/;
6019 my $net = PVE
::QemuServer
::parse_net
($conf->{$opt});
6021 my $romfile = PVE
::QemuServer
::vm_mon_cmd_nocheck
($vmid, 'qom-get', path
=> $opt, property
=> 'romfile');
6022 return $machine.".pxe" if $romfile =~ m/pxe/;
6029 sub qemu_use_old_bios_files
{
6030 my ($machine_type) = @_;
6032 return if !$machine_type;
6034 my $use_old_bios_files = undef;
6036 if ($machine_type =~ m/^(\S+)\.pxe$/) {
6038 $use_old_bios_files = 1;
6040 my $kvmver = kvm_user_version
();
6041 # Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
6042 # load new efi bios files on migration. So this hack is required to allow
6043 # live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
6044 # updrading from proxmox-ve-3.X to proxmox-ve 4.0
6045 $use_old_bios_files = !qemu_machine_feature_enabled
($machine_type, $kvmver, 2, 4);
6048 return ($use_old_bios_files, $machine_type);
6055 dir_glob_foreach
("$pcisysfs/devices", '[a-f0-9]{4}:([a-f0-9]{2}:[a-f0-9]{2})\.([0-9])', sub {
6056 my (undef, $id, $function) = @_;
6057 my $res = { id
=> $id, function
=> $function};
6058 push @{$devices->{$id}}, $res;
6064 sub vm_iothreads_list
{
6067 my $res = vm_mon_cmd
($vmid, 'query-iothreads');
6070 foreach my $iothread (@$res) {
6071 $iothreads->{ $iothread->{id
} } = $iothread->{"thread-id"};
6078 my ($conf, $drive) = @_;
6082 if ($conf->{scsihw
} && ($conf->{scsihw
} =~ m/^lsi/)) {
6084 } elsif ($conf->{scsihw
} && ($conf->{scsihw
} eq 'virtio-scsi-single')) {
6090 my $controller = int($drive->{index} / $maxdev);
6091 my $controller_prefix = ($conf->{scsihw
} && $conf->{scsihw
} eq 'virtio-scsi-single') ?
"virtioscsi" : "scsihw";
6093 return ($maxdev, $controller, $controller_prefix);
6096 # bash completion helper
6098 sub complete_backup_archives
{
6099 my ($cmdname, $pname, $cvalue) = @_;
6101 my $cfg = PVE
::Storage
::config
();
6105 if ($cvalue =~ m/^([^:]+):/) {
6109 my $data = PVE
::Storage
::template_list
($cfg, $storeid, 'backup');
6112 foreach my $id (keys %$data) {
6113 foreach my $item (@{$data->{$id}}) {
6114 next if $item->{format
} !~ m/^vma\.(gz|lzo)$/;
6115 push @$res, $item->{volid
} if defined($item->{volid
});
6122 my $complete_vmid_full = sub {
6125 my $idlist = vmstatus
();
6129 foreach my $id (keys %$idlist) {
6130 my $d = $idlist->{$id};
6131 if (defined($running)) {
6132 next if $d->{template
};
6133 next if $running && $d->{status
} ne 'running';
6134 next if !$running && $d->{status
} eq 'running';
6143 return &$complete_vmid_full();
6146 sub complete_vmid_stopped
{
6147 return &$complete_vmid_full(0);
6150 sub complete_vmid_running
{
6151 return &$complete_vmid_full(1);
6154 sub complete_storage
{
6156 my $cfg = PVE
::Storage
::config
();
6157 my $ids = $cfg->{ids
};
6160 foreach my $sid (keys %$ids) {
6161 next if !PVE
::Storage
::storage_check_enabled
($cfg, $sid, undef, 1);
6162 next if !$ids->{$sid}->{content
}->{images
};