line length and formatting fixes

In accord to updated perl style guide
https://pve.proxmox.com/wiki/Perl_Style_Guide#Breaking_long_lines_and_strings

Mostly try to avoid >100 column lines and update some descriptions
from 80 to 100 column limit, improving readability.

Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
Thomas Lamprecht 2020-09-02 14:07:02 +02:00
parent 6e5bda530e
commit 4df98f2f14

View File

@ -31,7 +31,7 @@ use PVE::DataCenterConfig;
use PVE::Exception qw(raise raise_param_exc);
use PVE::GuestHelpers qw(safe_string_ne safe_num_ne safe_boolean_ne);
use PVE::INotify;
use PVE::JSONSchema qw(get_standard_option);
use PVE::JSONSchema qw(get_standard_option parse_property_string);
use PVE::ProcFSTools;
use PVE::RPCEnvironment;
use PVE::Storage;
@ -445,9 +445,8 @@ EODESC
optional => 1,
type => 'boolean',
default => 0,
description => "Use together with hugepages. If enabled, hugepages will"
. " not be deleted after VM shutdown and can be used for"
. " subsequent starts.",
description => "Use together with hugepages. If enabled, hugepages will not not be deleted"
." after VM shutdown and can be used for subsequent starts.",
},
vcpus => {
optional => 1,
@ -483,7 +482,8 @@ EODESC
localtime => {
optional => 1,
type => 'boolean',
description => "Set the real time clock to local time. This is enabled by default if ostype indicates a Microsoft OS.",
description => "Set the real time clock to local time. This is enabled by default if ostype"
." indicates a Microsoft OS.",
},
freeze => {
optional => 1,
@ -494,29 +494,28 @@ EODESC
optional => 1,
type => 'string', format => $vga_fmt,
description => "Configure the VGA hardware.",
verbose_description => "Configure the VGA Hardware. If you want to use ".
"high resolution modes (>= 1280x1024x16) you may need to increase " .
"the vga memory option. Since QEMU 2.9 the default VGA display type " .
"is 'std' for all OS types besides some Windows versions (XP and " .
"older) which use 'cirrus'. The 'qxl' option enables the SPICE " .
"display server. For win* OS you can select how many independent " .
"displays you want, Linux guests can add displays them self.\n".
"You can also run without any graphic card, using a serial device as terminal.",
verbose_description => "Configure the VGA Hardware. If you want to use high resolution"
." modes (>= 1280x1024x16) you may need to increase the vga memory option. Since QEMU"
." 2.9 the default VGA display type is 'std' for all OS types besides some Windows"
." versions (XP and older) which use 'cirrus'. The 'qxl' option enables the SPICE"
." display server. For win* OS you can select how many independent displays you want,"
." Linux guests can add displays them self.\nYou can also run without any graphic card,"
." using a serial device as terminal.",
},
watchdog => {
optional => 1,
type => 'string', format => 'pve-qm-watchdog',
description => "Create a virtual hardware watchdog device.",
verbose_description => "Create a virtual hardware watchdog device. Once enabled" .
" (by a guest action), the watchdog must be periodically polled " .
"by an agent inside the guest or else the watchdog will reset " .
"the guest (or execute the respective action specified)",
verbose_description => "Create a virtual hardware watchdog device. Once enabled (by a guest"
." action), the watchdog must be periodically polled by an agent inside the guest or"
." else the watchdog will reset the guest (or execute the respective action specified)",
},
startdate => {
optional => 1,
type => 'string',
typetext => "(now | YYYY-MM-DD | YYYY-MM-DDTHH:MM:SS)",
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'.",
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'.",
pattern => '(now|\d{4}-\d{1,2}-\d{1,2}(T\d{1,2}:\d{1,2}:\d{1,2})?)',
default => 'now',
},
@ -544,12 +543,11 @@ EODESCR
type => 'boolean',
default => 1,
description => "Enable/disable the USB tablet device.",
verbose_description => "Enable/disable the USB tablet device. This device is " .
"usually needed to allow absolute mouse positioning with VNC. " .
"Else the mouse runs out of sync with normal VNC clients. " .
"If you're running lots of console-only guests on one host, " .
"you may consider disabling this to save some context switches. " .
"This is turned off by default if you use spice (-vga=qxl).",
verbose_description => "Enable/disable the USB tablet device. This device is usually needed"
." to allow absolute mouse positioning with VNC. Else the mouse runs out of sync with"
." normal VNC clients. If you're running lots of console-only guests on one host, you"
." may consider disabling this to save some context switches. This is turned off by"
." default if you use spice (`qm set <vmid> --vga qxl`).",
},
migrate_speed => {
optional => 1,
@ -590,17 +588,20 @@ EODESCR
vmstate => {
optional => 1,
type => 'string', format => 'pve-volume-id',
description => "Reference to a volume which stores the VM state. This is used internally for snapshots.",
description => "Reference to a volume which stores the VM state. This is used internally"
." for snapshots.",
},
vmstatestorage => get_standard_option('pve-storage-id', {
description => "Default storage for VM state volumes/files.",
optional => 1,
}),
runningmachine => get_standard_option('pve-qemu-machine', {
description => "Specifies the QEMU machine type of the running vm. This is used internally for snapshots.",
description => "Specifies the QEMU machine type of the running vm. This is used internally"
." for snapshots.",
}),
runningcpu => {
description => "Specifies the QEMU '-cpu' parameter of the running vm. This is used internally for snapshots.",
description => "Specifies the QEMU '-cpu' parameter of the running vm. This is used"
." internally for snapshots.",
optional => 1,
type => 'string',
pattern => $PVE::QemuServer::CPUConfig::qemu_cmdline_cpu_re,
@ -622,7 +623,8 @@ EODESCR
protection => {
optional => 1,
type => 'boolean',
description => "Sets the protection flag of the VM. This will disable the remove VM and remove disk operations.",
description => "Sets the protection flag of the VM. This will disable the remove VM and"
." remove disk operations.",
default => 0,
},
bios => {
@ -636,17 +638,16 @@ EODESCR
type => 'string',
pattern => '(?:[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}|[01])',
format_description => 'UUID',
description => "Set VM Generation ID. Use '1' to autogenerate on create or update, pass '0' to disable explicitly.",
verbose_description => "The VM generation ID (vmgenid) device exposes a".
" 128-bit integer value identifier to the guest OS. This allows to".
" notify the guest operating system when the virtual machine is".
" executed with a different configuration (e.g. snapshot execution".
" or creation from a template). The guest operating system notices".
" the change, and is then able to react as appropriate by marking".
" its copies of distributed databases as dirty, re-initializing its".
" random number generator, etc.\n".
"Note that auto-creation only works when done throug API/CLI create".
" or update methods, but not when manually editing the config file.",
description => "Set VM Generation ID. Use '1' to autogenerate on create or update, pass '0'"
." to disable explicitly.",
verbose_description => "The VM generation ID (vmgenid) device exposes a 128-bit integer"
." value identifier to the guest OS. This allows to notify the guest operating system"
." when the virtual machine is executed with a different configuration (e.g. snapshot"
." execution or creation from a template). The guest operating system notices the"
." change, and is then able to react as appropriate by marking its copies of"
." distributed databases as dirty, re-initializing its random number generator, etc.\n"
."Note that auto-creation only works when done through API/CLI create or update methods"
.", but not when manually editing the config file.",
default => "1 (autogenerated)",
optional => 1,
},
@ -659,7 +660,8 @@ EODESCR
ivshmem => {
type => 'string',
format => $ivshmem_fmt,
description => "Inter-VM shared memory. Useful for direct communication between VMs, or to the host.",
description => "Inter-VM shared memory. Useful for direct communication between VMs, or to"
." the host.",
optional => 1,
},
audio0 => {
@ -691,21 +693,24 @@ my $cicustom_fmt = {
meta => {
type => 'string',
optional => 1,
description => 'Specify a custom file containing all meta data passed to the VM via cloud-init. This is provider specific meaning configdrive2 and nocloud differ.',
description => 'Specify a custom file containing all meta data passed to the VM via"
." cloud-init. This is provider specific meaning configdrive2 and nocloud differ.',
format => 'pve-volume-id',
format_description => 'volume',
},
network => {
type => 'string',
optional => 1,
description => 'Specify a custom file containing all network data passed to the VM via cloud-init.',
description => 'Specify a custom file containing all network data passed to the VM via'
.' cloud-init.',
format => 'pve-volume-id',
format_description => 'volume',
},
user => {
type => 'string',
optional => 1,
description => 'Specify a custom file containing all user data passed to the VM via cloud-init.',
description => 'Specify a custom file containing all user data passed to the VM via'
.' cloud-init.',
format => 'pve-volume-id',
format_description => 'volume',
},
@ -716,34 +721,44 @@ my $confdesc_cloudinit = {
citype => {
optional => 1,
type => 'string',
description => 'Specifies the cloud-init configuration format. The default depends on the configured operating system type (`ostype`. We use the `nocloud` format for Linux, and `configdrive2` for windows.',
description => 'Specifies the cloud-init configuration format. The default depends on the'
.' configured operating system type (`ostype`. We use the `nocloud` format for Linux,'
.' and `configdrive2` for windows.',
enum => ['configdrive2', 'nocloud'],
},
ciuser => {
optional => 1,
type => 'string',
description => "cloud-init: User name to change ssh keys and password for instead of the image's configured default user.",
description => "cloud-init: User name to change ssh keys and password for instead of the"
." image's configured default user.",
},
cipassword => {
optional => 1,
type => 'string',
description => 'cloud-init: Password to assign the user. Using this is generally not recommended. Use ssh keys instead. Also note that older cloud-init versions do not support hashed passwords.',
description => 'cloud-init: Password to assign the user. Using this is generally not'
.' recommended. Use ssh keys instead. Also note that older cloud-init versions do not'
.' support hashed passwords.',
},
cicustom => {
optional => 1,
type => 'string',
description => 'cloud-init: Specify custom files to replace the automatically generated ones at start.',
description => 'cloud-init: Specify custom files to replace the automatically generated'
.' ones at start.',
format => 'pve-qm-cicustom',
},
searchdomain => {
optional => 1,
type => 'string',
description => "cloud-init: Sets DNS search domains for a container. Create will automatically use the setting from the host if neither searchdomain nor nameserver are set.",
description => "cloud-init: Sets DNS search domains for a container. Create will'
.' automatically use the setting from the host if neither searchdomain nor nameserver'
.' are set.",
},
nameserver => {
optional => 1,
type => 'string', format => 'address-list',
description => "cloud-init: Sets DNS server IP address for a container. Create will automatically use the setting from the host if neither searchdomain nor nameserver are set.",
description => "cloud-init: Sets DNS server IP address for a container. Create will'
.' automatically use the setting from the host if neither searchdomain nor nameserver'
.' are set.",
},
sshkeys => {
optional => 1,
@ -840,11 +855,14 @@ __EOD__
my $net_fmt = {
macaddr => get_standard_option('mac-addr', {
description => "MAC address. That address must be unique withing your network. This is automatically generated if not specified.",
description => "MAC address. That address must be unique withing your network. This is"
." automatically generated if not specified.",
}),
model => {
type => 'string',
description => "Network Card Model. The 'virtio' model provides the best performance with very low CPU overhead. If your guest does not support this driver, it is usually best to use 'e1000'.",
description => "Network Card Model. The 'virtio' model provides the best performance with"
." very low CPU overhead. If your guest does not support this driver, it is usually"
." best to use 'e1000'.",
enum => $nic_model_list,
default_key => 1,
},
@ -950,10 +968,12 @@ cloud-init: Specify IP addresses and gateways for the corresponding interface.
IP addresses use CIDR notation, gateways are optional but need an IP of the same type specified.
The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit gateway should be provided.
The special string 'dhcp' can be used for IP addresses to use DHCP, in which case no explicit
gateway should be provided.
For IPv6 the special string 'auto' can be used to use stateless autoconfiguration.
If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using dhcp on IPv4.
If cloud-init is enabled and neither an IPv4 nor an IPv6 address is specified, it defaults to using
dhcp on IPv4.
EODESCR
};
PVE::JSONSchema::register_standard_option("pve-qm-ipconfig", $netdesc);
@ -998,7 +1018,8 @@ The Host USB device or port or the value 'spice'. HOSTUSBDEVICE syntax is:
You can use the 'lsusb -t' command to list existing usb devices.
NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such
machines - use with special care.
The value 'spice' can be used to add a usb redirection devices for spice.
EODESCR
@ -1028,7 +1049,8 @@ 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).
NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines - use with special care.
NOTE: If you pass through a host serial device, it is no longer possible to migrate such machines -
use with special care.
CAUTION: Experimental! User reported problems with this option.
EODESCR
@ -1042,7 +1064,8 @@ my $paralleldesc= {
verbose_description => <<EODESCR,
Map host parallel devices (n is 0 to 2).
NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such machines - use with special care.
NOTE: This option allows direct access to host hardware. So it is no longer possible to migrate such
machines - use with special care.
CAUTION: Experimental! User reported problems with this option.
EODESCR
@ -1111,6 +1134,11 @@ sub kvm_user_version {
return $kvm_user_version->{$binary};
}
my sub extract_version {
my ($machine_type, $version) = @_;
$version = kvm_user_version() if !defined($version);
PVE::QemuServer::Machine::extract_version($machine_type, $version)
}
sub kernel_has_vhost_net {
return -c '/dev/vhost-net';
@ -1193,7 +1221,8 @@ sub cleanup_drive_path {
($drive->{file} !~ m/^([^:]+):(.+)$/) &&
($drive->{file} !~ m/^\d+$/)) {
my ($vtype, $volid) = PVE::Storage::path_to_volume_id($storecfg, $drive->{file});
raise_param_exc({ $opt => "unable to associate path '$drive->{file}' to any storage"}) if !$vtype;
raise_param_exc({ $opt => "unable to associate path '$drive->{file}' to any storage"})
if !$vtype;
$drive->{media} = 'cdrom' if !$drive->{media} && $vtype eq 'iso';
verify_media_type($opt, $vtype, $drive->{media});
$drive->{file} = $volid;
@ -1323,10 +1352,11 @@ sub print_drivedevice_full {
my $device = '';
my $maxdev = 0;
my $drive_id = "$drive->{interface}$drive->{index}";
if ($drive->{interface} eq 'virtio') {
my $pciaddr = print_pci_addr("$drive->{interface}$drive->{index}", $bridges, $arch, $machine_type);
$device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
$device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread};
my $pciaddr = print_pci_addr("$drive_id", $bridges, $arch, $machine_type);
$device = "virtio-blk-pci,drive=drive-$drive_id,id=${drive_id}${pciaddr}";
$device .= ",iothread=iothread-$drive_id" if $drive->{iothread};
} elsif ($drive->{interface} eq 'scsi') {
my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $drive);
@ -1350,7 +1380,7 @@ sub print_drivedevice_full {
}
# for compatibility only, we prefer scsi-hd (#2408, #2355, #2380)
my $version = PVE::QemuServer::Machine::extract_version($machine_type, kvm_user_version());
my $version = extract_version($machine_type, kvm_user_version());
if ($path =~ m/^iscsi\:\/\// &&
!min_version($version, 4, 1)) {
$devicetype = 'generic';
@ -1358,10 +1388,12 @@ sub print_drivedevice_full {
}
if (!$conf->{scsihw} || ($conf->{scsihw} =~ m/^lsi/)){
$device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
$device = "scsi-$devicetype,bus=$controller_prefix$controller.0,scsi-id=$unit";
} else {
$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}";
$device = "scsi-$devicetype,bus=$controller_prefix$controller.0,channel=0,scsi-id=0"
.",lun=$drive->{index}";
}
$device .= ",drive=drive-$drive_id,id=$drive_id";
if ($drive->{ssd} && ($devicetype eq 'block' || $devicetype eq 'hd')) {
$device .= ",rotation_rate=1";
@ -1380,7 +1412,7 @@ sub print_drivedevice_full {
} else {
$device .= ",bus=ahci$controller.$unit";
}
$device .= ",drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}";
$device .= ",drive=drive-$drive_id,id=$drive_id";
if ($devicetype eq 'hd') {
if (my $model = $drive->{model}) {
@ -1530,7 +1562,8 @@ sub print_netdevice_full {
my $pciaddr = print_pci_addr("$netid", $bridges, $arch, $machine_type);
my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
if ($net->{queues} && $net->{queues} > 1 && $net->{model} eq 'virtio'){
#Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
# Consider we have N queues, the number of vectors needed is 2 * N + 2, i.e., one per in
# and out of each queue plus one config interrupt and control vector queue
my $vectors = $net->{queues} * 2 + 2;
$tmpstr .= ",vectors=$vectors,mq=on";
}
@ -1598,7 +1631,8 @@ sub print_netdev_full {
my $script = $hotplug ? "pve-bridge-hotplug" : "pve-bridge";
if ($net->{bridge}) {
$netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script,downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
$netdev = "type=tap,id=$netid,ifname=${ifname},script=/var/lib/qemu-server/$script"
.",downscript=/var/lib/qemu-server/pve-bridgedown$vhostparam";
} else {
$netdev = "type=user,id=$netid,hostname=$vmname";
}
@ -1692,7 +1726,7 @@ sub parse_number_sets {
sub parse_numa {
my ($data) = @_;
my $res = PVE::JSONSchema::parse_property_string($numa_fmt, $data);
my $res = parse_property_string($numa_fmt, $data);
$res->{cpus} = parse_number_sets($res->{cpus}) if defined($res->{cpus});
$res->{hostnodes} = parse_number_sets($res->{hostnodes}) if defined($res->{hostnodes});
return $res;
@ -1702,7 +1736,7 @@ sub parse_numa {
sub parse_net {
my ($data) = @_;
my $res = eval { PVE::JSONSchema::parse_property_string($net_fmt, $data) };
my $res = eval { parse_property_string($net_fmt, $data) };
if ($@) {
warn $@;
return undef;
@ -1718,7 +1752,7 @@ sub parse_net {
sub parse_ipconfig {
my ($data) = @_;
my $res = eval { PVE::JSONSchema::parse_property_string($ipconfig_fmt, $data) };
my $res = eval { parse_property_string($ipconfig_fmt, $data) };
if ($@) {
warn $@;
return undef;
@ -1855,7 +1889,7 @@ my $smbios1_fmt = {
sub parse_smbios1 {
my ($data) = @_;
my $res = eval { PVE::JSONSchema::parse_property_string($smbios1_fmt, $data) };
my $res = eval { parse_property_string($smbios1_fmt, $data) };
warn $@ if $@;
return $res;
}
@ -1872,7 +1906,7 @@ sub parse_watchdog {
return undef if !$value;
my $res = eval { PVE::JSONSchema::parse_property_string($watchdog_fmt, $value) };
my $res = eval { parse_property_string($watchdog_fmt, $value) };
warn $@ if $@;
return $res;
}
@ -1882,7 +1916,7 @@ sub parse_guest_agent {
return {} if !defined($value->{agent});
my $res = eval { PVE::JSONSchema::parse_property_string($agent_fmt, $value->{agent}) };
my $res = eval { parse_property_string($agent_fmt, $value->{agent}) };
warn $@ if $@;
# if the agent is disabled ignore the other potentially set properties
@ -1894,7 +1928,7 @@ sub parse_vga {
my ($value) = @_;
return {} if !$value;
my $res = eval { PVE::JSONSchema::parse_property_string($vga_fmt, $value) };
my $res = eval { parse_property_string($vga_fmt, $value) };
warn $@ if $@;
return $res;
}
@ -1904,7 +1938,7 @@ sub parse_rng {
return undef if !$value;
my $res = eval { PVE::JSONSchema::parse_property_string($rng_fmt, $value) };
my $res = eval { parse_property_string($rng_fmt, $value) };
warn $@ if $@;
return $res;
}
@ -2210,7 +2244,7 @@ sub write_vm_config {
}
foreach my $key (sort keys %$conf) {
next if $key eq 'digest' || $key eq 'description' || $key eq 'pending' || $key eq 'snapshots';
next if $key =~ /^(digest|description|pending|snapshots)$/;
$raw .= "$key: $conf->{$key}\n";
}
return $raw;
@ -2687,7 +2721,7 @@ sub conf_has_audio {
my $audio = $conf->{"audio$id"};
return undef if !defined($audio);
my $audioproperties = PVE::JSONSchema::parse_property_string($audio_fmt, $audio);
my $audioproperties = parse_property_string($audio_fmt, $audio);
my $audiodriver = $audioproperties->{driver} // 'spice';
return {
@ -2941,7 +2975,7 @@ sub config_to_command {
my $add_pve_version = min_version($kvmver, 4, 1);
my $machine_type = get_vm_machine($conf, $forcemachine, $arch, $add_pve_version);
my $machine_version = PVE::QemuServer::Machine::extract_version($machine_type, $kvmver);
my $machine_version = extract_version($machine_type, $kvmver);
$kvm //= 1 if is_native($arch);
$machine_version =~ m/(\d+)\.(\d+)/;
@ -2950,11 +2984,13 @@ sub config_to_command {
if ($kvmver =~ m/^\d+\.\d+\.(\d+)/ && $1 >= 90) {
warn "warning: Installed QEMU version ($kvmver) is a release candidate, ignoring version checks\n";
} elsif (!min_version($kvmver, $machine_major, $machine_minor)) {
die "Installed QEMU version '$kvmver' is too old to run machine type '$machine_type', please upgrade node '$nodename'\n"
die "Installed QEMU version '$kvmver' is too old to run machine type '$machine_type',"
." please upgrade node '$nodename'\n"
} elsif (!PVE::QemuServer::Machine::can_run_pve_machine_version($machine_version, $kvmver)) {
my $max_pve_version = PVE::QemuServer::Machine::get_pve_version($machine_version);
die "Installed qemu-server (max feature level for $machine_major.$machine_minor is pve$max_pve_version)"
." is too old to run machine type '$machine_type', please upgrade node '$nodename'\n";
die "Installed qemu-server (max feature level for $machine_major.$machine_minor is"
." pve$max_pve_version) is too old to run machine type '$machine_type', please upgrade"
." node '$nodename'\n";
}
# if a specific +pve version is required for a feature, use $version_guard
@ -2970,9 +3006,9 @@ sub config_to_command {
return 1;
};
if ($kvm) {
die "KVM virtualisation configured, but not available. Either disable in VM configuration or enable in BIOS.\n"
if !defined kvm_version();
if ($kvm && !defined kvm_version()) {
die "KVM virtualisation configured, but not available. Either disable in VM configuration"
." or enable in BIOS.\n";
}
my $q35 = PVE::QemuServer::Machine::machine_type_is_q35($conf);
@ -3081,7 +3117,8 @@ sub config_to_command {
}
# add usb controllers
my @usbcontrollers = PVE::QemuServer::USB::get_usb_controllers($conf, $bridges, $arch, $machine_type, $usbdesc->{format}, $MAX_USB_DEVICES);
my @usbcontrollers = PVE::QemuServer::USB::get_usb_controllers(
$conf, $bridges, $arch, $machine_type, $usbdesc->{format}, $MAX_USB_DEVICES);
push @$devices, @usbcontrollers if @usbcontrollers;
my $vga = parse_vga($conf->{vga});
@ -3122,7 +3159,8 @@ sub config_to_command {
my $usb_dev_features = {};
$usb_dev_features->{spice_usb3} = 1 if min_version($machine_version, 4, 0);
my @usbdevices = PVE::QemuServer::USB::get_usb_devices($conf, $usbdesc->{format}, $MAX_USB_DEVICES, $usb_dev_features);
my @usbdevices = PVE::QemuServer::USB::get_usb_devices(
$conf, $usbdesc->{format}, $MAX_USB_DEVICES, $usb_dev_features);
push @$devices, @usbdevices if @usbdevices;
# serial devices
for (my $i = 0; $i < $MAX_SERIAL_PORTS; $i++) {
@ -3207,7 +3245,8 @@ sub config_to_command {
push @$cmd, '-no-reboot' if defined($conf->{reboot}) && $conf->{reboot} == 0;
if ($vga->{type} && $vga->{type} !~ m/^serial\d+$/ && $vga->{type} ne 'none'){
push @$devices, '-device', print_vga_device($conf, $vga, $arch, $machine_version, $machine_type, undef, $qxlnum, $bridges);
push @$devices, '-device', print_vga_device(
$conf, $vga, $arch, $machine_version, $machine_type, undef, $qxlnum, $bridges);
my $socket = PVE::QemuServer::Helpers::vnc_socket($vmid);
push @$cmd, '-vnc', "unix:$socket,password";
} else {
@ -3290,7 +3329,8 @@ sub config_to_command {
if ($qxlnum > 1) {
if ($winversion){
for (my $i = 1; $i < $qxlnum; $i++){
push @$devices, '-device', print_vga_device($conf, $vga, $arch, $machine_version, $machine_type, $i, $qxlnum, $bridges);
push @$devices, '-device', print_vga_device(
$conf, $vga, $arch, $machine_version, $machine_type, $i, $qxlnum, $bridges);
}
} else {
# assume other OS works like Linux
@ -3317,14 +3357,17 @@ sub config_to_command {
my $localhost = PVE::Network::addr_to_ip($nodeaddrs[0]->{addr});
$spice_port = PVE::Tools::next_spice_port($pfamily, $localhost);
my $spice_enhancement = PVE::JSONSchema::parse_property_string($spice_enhancements_fmt, $conf->{spice_enhancements} // '');
my $spice_enhancement_str = $conf->{spice_enhancements} // '';
my $spice_enhancement = parse_property_string($spice_enhancements_fmt, $spice_enhancement_str);
if ($spice_enhancement->{foldersharing}) {
push @$devices, '-chardev', "spiceport,id=foldershare,name=org.spice-space.webdav.0";
push @$devices, '-device', "virtserialport,chardev=foldershare,name=org.spice-space.webdav.0";
}
my $spice_opts = "tls-port=${spice_port},addr=$localhost,tls-ciphers=HIGH,seamless-migration=on";
$spice_opts .= ",streaming-video=$spice_enhancement->{videostreaming}" if $spice_enhancement->{videostreaming};
$spice_opts .= ",streaming-video=$spice_enhancement->{videostreaming}"
if $spice_enhancement->{videostreaming};
push @$devices, '-spice', "$spice_opts";
}
@ -3403,14 +3446,16 @@ sub config_to_command {
$queues = ",num_queues=$drive->{queues}";
}
push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues" if !$scsicontroller->{$controller};
push @$devices, '-device', "$scsihw_type,id=$controller_prefix$controller$pciaddr$iothread$queues"
if !$scsicontroller->{$controller};
$scsicontroller->{$controller}=1;
}
if ($drive->{interface} eq 'sata') {
my $controller = int($drive->{index} / $PVE::QemuServer::Drive::MAX_SATA_DISKS);
$pciaddr = print_pci_addr("ahci$controller", $bridges, $arch, $machine_type);
push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr"
if !$ahcicontroller->{$controller};
$ahcicontroller->{$controller}=1;
}
@ -3418,7 +3463,8 @@ sub config_to_command {
$drive_cmd .= ',readonly' if PVE::QemuConfig->is_template($conf);
push @$devices, '-drive',$drive_cmd;
push @$devices, '-device', print_drivedevice_full($storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type);
push @$devices, '-device', print_drivedevice_full(
$storecfg, $conf, $vmid, $drive, $bridges, $arch, $machine_type);
});
for (my $i = 0; $i < $MAX_NETS; $i++) {
@ -3436,12 +3482,14 @@ sub config_to_command {
my $netdevfull = print_netdev_full($vmid, $conf, $arch, $d, "net$i");
push @$devices, '-netdev', $netdevfull;
my $netdevicefull = print_netdevice_full($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files, $arch, $machine_type);
my $netdevicefull = print_netdevice_full(
$vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files, $arch, $machine_type);
push @$devices, '-device', $netdevicefull;
}
if ($conf->{ivshmem}) {
my $ivshmem = PVE::JSONSchema::parse_property_string($ivshmem_fmt, $conf->{ivshmem});
my $ivshmem = parse_property_string($ivshmem_fmt, $conf->{ivshmem});
my $bus;
if ($q35) {
@ -3454,7 +3502,8 @@ sub config_to_command {
my $path = '/dev/shm/pve-shm-' . $ivshmem_name;
push @$devices, '-device', "ivshmem-plain,memdev=ivshmem$bus,";
push @$devices, '-object', "memory-backend-file,id=ivshmem,share=on,mem-path=$path,size=$ivshmem->{size}M";
push @$devices, '-object', "memory-backend-file,id=ivshmem,share=on,mem-path=$path"
.",size=$ivshmem->{size}M";
}
# pci.4 is nested in pci.1
@ -3530,12 +3579,11 @@ sub check_rng_source {
my $rng_current = '/sys/devices/virtual/misc/hw_random/rng_current';
if ($source eq '/dev/hwrng' && file_read_firstline($rng_current) eq 'none') {
# Needs to abort, otherwise QEMU crashes on first rng access.
# Note that rng_current cannot be changed to 'none' manually, so
# once the VM is past this point, it is no longer an issue.
die "Cannot start VM with passed-through RNG device: '/dev/hwrng'"
. " exists, but '$rng_current' is set to 'none'. Ensure that"
. " a compatible hardware-RNG is attached to the host.\n";
# Needs to abort, otherwise QEMU crashes on first rng access. Note that rng_current cannot
# be changed to 'none' manually, so once the VM is past this point, it's no longer an issue.
die "Cannot start VM with passed-through RNG device: '/dev/hwrng' exists, but"
." '$rng_current' is set to 'none'. Ensure that a compatible hardware-RNG is attached"
." to the host.\n";
}
}
@ -3605,7 +3653,8 @@ sub vm_deviceplug {
my $devices_list = vm_devices_list($vmid);
return 1 if defined($devices_list->{$deviceid});
qemu_add_pci_bridge($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type); # add PCI bridge if we need it for the device
# add PCI bridge if we need it for the device
qemu_add_pci_bridge($storecfg, $conf, $vmid, $deviceid, $arch, $machine_type);
if ($deviceid eq 'tablet') {
@ -3680,7 +3729,8 @@ sub vm_deviceplug {
my $use_old_bios_files = undef;
($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
my $netdevicefull = print_netdevice_full($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
my $netdevicefull = print_netdevice_full(
$vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $machine_type);
qemu_deviceadd($vmid, $netdevicefull);
eval {
qemu_deviceaddverify($vmid, $deviceid);
@ -4410,7 +4460,7 @@ sub vmconfig_hotplug_pending {
# since we cannot reliably hot unplug usb devices
# we are disabling it
die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
my $d = eval { parse_property_string($usbdesc->{format}, $value) };
die "skip\n" if !$d;
qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $machine_type);
} elsif ($opt eq 'vcpus') {
@ -4612,102 +4662,100 @@ sub vmconfig_update_disk {
my $drive = parse_drive($opt, $value);
if ($conf->{$opt}) {
if ($conf->{$opt} && (my $old_drive = parse_drive($opt, $conf->{$opt}))) {
my $media = $drive->{media} || 'disk';
my $oldmedia = $old_drive->{media} || 'disk';
die "unable to change media type\n" if $media ne $oldmedia;
if (my $old_drive = parse_drive($opt, $conf->{$opt})) {
if (!drive_is_cdrom($old_drive)) {
my $media = $drive->{media} || 'disk';
my $oldmedia = $old_drive->{media} || 'disk';
die "unable to change media type\n" if $media ne $oldmedia;
if ($drive->{file} ne $old_drive->{file}) {
if (!drive_is_cdrom($old_drive)) {
die "skip\n" if !$hotplug;
if ($drive->{file} ne $old_drive->{file}) {
# unplug and register as unused
vm_deviceunplug($vmid, $conf, $opt);
vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
die "skip\n" if !$hotplug;
} else {
# update existing disk
# unplug and register as unused
vm_deviceunplug($vmid, $conf, $opt);
vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive)
# skip non hotpluggable value
if (safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
safe_string_ne($drive->{cache}, $old_drive->{cache}) ||
safe_string_ne($drive->{ssd}, $old_drive->{ssd})) {
die "skip\n";
}
} else {
# update existing disk
# apply throttle
if (safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
# skip non hotpluggable value
if (safe_string_ne($drive->{discard}, $old_drive->{discard}) ||
safe_string_ne($drive->{iothread}, $old_drive->{iothread}) ||
safe_string_ne($drive->{queues}, $old_drive->{queues}) ||
safe_string_ne($drive->{cache}, $old_drive->{cache}) ||
safe_string_ne($drive->{ssd}, $old_drive->{ssd})) {
die "skip\n";
}
qemu_block_set_io_throttle(
$vmid,"drive-$opt",
($drive->{mbps} || 0)*1024*1024,
($drive->{mbps_rd} || 0)*1024*1024,
($drive->{mbps_wr} || 0)*1024*1024,
$drive->{iops} || 0,
$drive->{iops_rd} || 0,
$drive->{iops_wr} || 0,
($drive->{mbps_max} || 0)*1024*1024,
($drive->{mbps_rd_max} || 0)*1024*1024,
($drive->{mbps_wr_max} || 0)*1024*1024,
$drive->{iops_max} || 0,
$drive->{iops_rd_max} || 0,
$drive->{iops_wr_max} || 0,
$drive->{bps_max_length} || 1,
$drive->{bps_rd_max_length} || 1,
$drive->{bps_wr_max_length} || 1,
$drive->{iops_max_length} || 1,
$drive->{iops_rd_max_length} || 1,
$drive->{iops_wr_max_length} || 1,
);
# apply throttle
if (safe_num_ne($drive->{mbps}, $old_drive->{mbps}) ||
safe_num_ne($drive->{mbps_rd}, $old_drive->{mbps_rd}) ||
safe_num_ne($drive->{mbps_wr}, $old_drive->{mbps_wr}) ||
safe_num_ne($drive->{iops}, $old_drive->{iops}) ||
safe_num_ne($drive->{iops_rd}, $old_drive->{iops_rd}) ||
safe_num_ne($drive->{iops_wr}, $old_drive->{iops_wr}) ||
safe_num_ne($drive->{mbps_max}, $old_drive->{mbps_max}) ||
safe_num_ne($drive->{mbps_rd_max}, $old_drive->{mbps_rd_max}) ||
safe_num_ne($drive->{mbps_wr_max}, $old_drive->{mbps_wr_max}) ||
safe_num_ne($drive->{iops_max}, $old_drive->{iops_max}) ||
safe_num_ne($drive->{iops_rd_max}, $old_drive->{iops_rd_max}) ||
safe_num_ne($drive->{iops_wr_max}, $old_drive->{iops_wr_max}) ||
safe_num_ne($drive->{bps_max_length}, $old_drive->{bps_max_length}) ||
safe_num_ne($drive->{bps_rd_max_length}, $old_drive->{bps_rd_max_length}) ||
safe_num_ne($drive->{bps_wr_max_length}, $old_drive->{bps_wr_max_length}) ||
safe_num_ne($drive->{iops_max_length}, $old_drive->{iops_max_length}) ||
safe_num_ne($drive->{iops_rd_max_length}, $old_drive->{iops_rd_max_length}) ||
safe_num_ne($drive->{iops_wr_max_length}, $old_drive->{iops_wr_max_length})) {
qemu_block_set_io_throttle($vmid,"drive-$opt",
($drive->{mbps} || 0)*1024*1024,
($drive->{mbps_rd} || 0)*1024*1024,
($drive->{mbps_wr} || 0)*1024*1024,
$drive->{iops} || 0,
$drive->{iops_rd} || 0,
$drive->{iops_wr} || 0,
($drive->{mbps_max} || 0)*1024*1024,
($drive->{mbps_rd_max} || 0)*1024*1024,
($drive->{mbps_wr_max} || 0)*1024*1024,
$drive->{iops_max} || 0,
$drive->{iops_rd_max} || 0,
$drive->{iops_wr_max} || 0,
$drive->{bps_max_length} || 1,
$drive->{bps_rd_max_length} || 1,
$drive->{bps_wr_max_length} || 1,
$drive->{iops_max_length} || 1,
$drive->{iops_rd_max_length} || 1,
$drive->{iops_wr_max_length} || 1);
}
return 1;
}
} else { # cdrom
if ($drive->{file} eq 'none') {
mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
if (drive_is_cloudinit($old_drive)) {
vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
}
} else {
my $path = get_iso_path($storecfg, $vmid, $drive->{file});
# force eject if locked
mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
if ($path) {
mon_cmd($vmid, "blockdev-change-medium",
id => "$opt", filename => "$path");
}
}
return 1;
}
} else { # cdrom
if ($drive->{file} eq 'none') {
mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
if (drive_is_cloudinit($old_drive)) {
vmconfig_register_unused_drive($storecfg, $vmid, $conf, $old_drive);
}
} else {
my $path = get_iso_path($storecfg, $vmid, $drive->{file});
# force eject if locked
mon_cmd($vmid, "eject", force => JSON::true, id => "$opt");
if ($path) {
mon_cmd($vmid, "blockdev-change-medium",
id => "$opt", filename => "$path");
}
}
return 1;
}
}
@ -4774,7 +4822,8 @@ sub vm_migrate_alloc_nbd_disks {
$format = qemu_img_format($scfg, $volname);
}
my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, ($drive->{size}/1024));
my $size = $drive->{size} / 1024;
my $newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $format, undef, $size);
my $newdrive = $drive;
$newdrive->{format} = $format;
$newdrive->{file} = $newvolid;
@ -5086,7 +5135,13 @@ sub vm_start_nolock {
my $pfamily = PVE::Tools::get_host_address_family($nodename);
my $storage_migrate_port = PVE::Tools::next_migrate_port($pfamily);
mon_cmd($vmid, "nbd-server-start", addr => { type => 'inet', data => { host => "${localip}", port => "${storage_migrate_port}" } } );
mon_cmd($vmid, "nbd-server-start", addr => {
type => 'inet',
data => {
host => "${localip}",
port => "${storage_migrate_port}",
},
});
$localip = "[$localip]" if Net::IP::ip_is_ipv6($localip);
$migrate_storage_uri = "nbd:${localip}:${storage_migrate_port}";
}
@ -5117,7 +5172,8 @@ sub vm_start_nolock {
print "spice listens on port $spice_port\n";
$res->{spice_port} = $spice_port;
if ($migrate_opts->{spice_ticket}) {
mon_cmd($vmid, "set_password", protocol => 'spice', password => $migrate_opts->{spice_ticket});
mon_cmd($vmid, "set_password", protocol => 'spice', password =>
$migrate_opts->{spice_ticket});
mon_cmd($vmid, "expire_password", protocol => 'spice', time => "+30");
}
}
@ -5227,7 +5283,7 @@ sub vm_stop_cleanup {
}
if ($conf->{ivshmem}) {
my $ivshmem = PVE::JSONSchema::parse_property_string($ivshmem_fmt, $conf->{ivshmem});
my $ivshmem = parse_property_string($ivshmem_fmt, $conf->{ivshmem});
# just delete it for now, VMs which have this already open do not
# are affected, but new VMs will get a separated one. If this
# becomes an issue we either add some sort of ref-counting or just
@ -5413,7 +5469,8 @@ sub vm_suspend {
}
$vmstate = PVE::QemuConfig->__snapshot_save_vmstate($vmid, $conf, "suspend-$date", $storecfg, $statestorage, 1);
$vmstate = PVE::QemuConfig->__snapshot_save_vmstate(
$vmid, $conf, "suspend-$date", $storecfg, $statestorage, 1);
$path = PVE::Storage::path($storecfg, $vmstate);
PVE::QemuConfig->write_config($vmid, $conf);
} else {
@ -5696,7 +5753,8 @@ my $restore_allocate_devices = sub {
$name .= ".$d->{format}" if $d->{format} ne 'raw';
}
my $volid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $vmid, $d->{format}, $name, $alloc_size);
my $volid = PVE::Storage::vdisk_alloc(
$storecfg, $storeid, $vmid, $d->{format}, $name, $alloc_size);
print STDERR "new volume ID is '$volid'\n";
$d->{volid} = $volid;
@ -5842,18 +5900,18 @@ sub update_disk_config {
my $volid = $drive->{file};
return if !$volid;
my $volume = $volid_hash->{$volid};
# mark volid as "in-use" for next step
$referenced->{$volid} = 1;
if ($volid_hash->{$volid} &&
(my $path = $volid_hash->{$volid}->{path})) {
if ($volume && (my $path = $volume->{path})) {
$referencedpath->{$path} = 1;
}
return if drive_is_cdrom($drive);
return if !$volid_hash->{$volid};
return if !$volume;
my ($updated, $msg) = PVE::QemuServer::Drive::update_disksize($drive, $volid_hash->{$volid}->{size});
my ($updated, $msg) = PVE::QemuServer::Drive::update_disksize($drive, $volume->{size});
if (defined($updated)) {
$changes = 1;
$conf->{$opt} = print_drive($updated);
@ -6022,7 +6080,9 @@ sub restore_proxmox_backup_archive {
}
}
my $is_qemu_server_backup = scalar(grep { $_->{filename} eq 'qemu-server.conf.blob' } @{$index->{files}});
my $is_qemu_server_backup = scalar(
grep { $_->{filename} eq 'qemu-server.conf.blob' } @{$index->{files}}
);
if (!$is_qemu_server_backup) {
die "backup does not look like a qemu-server backup (missing 'qemu-server.conf' file)\n";
}
@ -6847,7 +6907,8 @@ sub clone_disk {
} elsif ($drivename eq 'efidisk0') {
$size = get_efivars_size($conf);
}
$newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $newvmid, $dst_format, $name, ($size/1024));
$size /= 1024;
$newvolid = PVE::Storage::vdisk_alloc($storecfg, $storeid, $newvmid, $dst_format, $name, $size);
push @$newvollist, $newvolid;
PVE::Storage::activate_volumes($storecfg, [$newvolid]);
@ -6865,7 +6926,8 @@ sub clone_disk {
# that is given by the OVMF_VARS.fd
my $src_path = PVE::Storage::path($storecfg, $drive->{file});
my $dst_path = PVE::Storage::path($storecfg, $newvolid);
run_command(['qemu-img', 'dd', '-n', '-O', $dst_format, "bs=1", "count=$size", "if=$src_path", "of=$dst_path"]);
run_command(['qemu-img', 'dd', '-n', '-O', $dst_format, "bs=1", "count=$size",
"if=$src_path", "of=$dst_path"]);
} else {
qemu_img_convert($drive->{file}, $newvolid, $size, $snapname, $sparseinit);
}
@ -6877,7 +6939,8 @@ sub clone_disk {
if $drive->{iothread};
}
qemu_drive_mirror($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs, $completion, $qga, $bwlimit);
qemu_drive_mirror($vmid, $drivename, $newvolid, $newvmid, $sparseinit, $jobs,
$completion, $qga, $bwlimit);
}
}
@ -6909,7 +6972,7 @@ sub qemu_use_old_bios_files {
$machine_type = $1;
$use_old_bios_files = 1;
} else {
my $version = PVE::QemuServer::Machine::extract_version($machine_type, kvm_user_version());
my $version = extract_version($machine_type, kvm_user_version());
# Note: kvm version < 2.4 use non-efi pxe files, and have problems when we
# load new efi bios files on migration. So this hack is required to allow
# live migration from qemu-2.2 to qemu-2.4, which is sometimes used when
@ -6984,7 +7047,9 @@ sub scsihw_infos {
}
my $controller = int($drive->{index} / $maxdev);
my $controller_prefix = ($conf->{scsihw} && $conf->{scsihw} eq 'virtio-scsi-single') ? "virtioscsi" : "scsihw";
my $controller_prefix = ($conf->{scsihw} && $conf->{scsihw} eq 'virtio-scsi-single')
? "virtioscsi"
: "scsihw";
return ($maxdev, $controller, $controller_prefix);
}