]> git.proxmox.com Git - qemu-server.git/blobdiff - PVE/QemuServer.pm
Drop skiplock from write_config
[qemu-server.git] / PVE / QemuServer.pm
index 14a18f0cf7dc7c62d705148c47da60e7e68d5099..1139438c77a41e7a1ec84f9eee0a1d4fdd95a804 100644 (file)
@@ -727,16 +727,31 @@ my $alldrive_fmt = {
     %queues_fmt,
 };
 
+my $usbformat = {
+    host => {
+       default_key => 1,
+       type => 'string', format => 'pve-qm-usb-device',
+       format_description => 'HOSTUSBDEVICE|spice',
+       description => 'The Host USB device or port or the value spice',
+    },
+    usb3 => {
+       optional => 1,
+       type => 'boolean',
+       format_description => 'yes|no',
+       description => 'Specifies whether if given host option is a USB3 device or port',
+    },
+};
+
 my $usbdesc = {
     optional => 1,
-    type => 'string', format => 'pve-qm-usb-device',
-    typetext => 'host=HOSTUSBDEVICE|spice',
+    type => 'string', format => $usbformat,
     description => <<EODESCR,
 Configure an USB device (n is 0 to 4). This can be used to
 pass-through usb devices to the guest. HOSTUSBDEVICE syntax is:
 
 'bus-port(.port)*' (decimal numbers) or
-'vendor_id:product_id' (hexadeciaml numbers)
+'vendor_id:product_id' (hexadeciaml numbers) or
+'spice'
 
 You can use the 'lsusb -t' command to list existing usb devices.
 
@@ -744,6 +759,8 @@ Note: This option allows direct access to host hardware. So it is no longer poss
 
 The value 'spice' can be used to add a usb redirection devices for spice.
 
+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).
+
 EODESCR
 };
 PVE::JSONSchema::register_standard_option("pve-qm-usb", $usbdesc);
@@ -1814,27 +1831,18 @@ sub parse_usb_device {
 
     return undef if !$value;
 
-    my @dl = split(/,/, $value);
-    my $found;
-
     my $res = {};
-    foreach my $v (@dl) {
-       if ($v =~ m/^host=(0x)?([0-9A-Fa-f]{4}):(0x)?([0-9A-Fa-f]{4})$/) {
-           $found = 1;
-           $res->{vendorid} = $2;
-           $res->{productid} = $4;
-       } elsif ($v =~ m/^host=(\d+)\-(\d+(\.\d+)*)$/) {
-           $found = 1;
-           $res->{hostbus} = $1;
-           $res->{hostport} = $2;
-       } elsif ($v =~ m/^spice$/) {
-           $found = 1;
-           $res->{spice} = 1;
-       } else {
-           return undef;
-       }
+    if ($value =~ m/^(0x)?([0-9A-Fa-f]{4}):(0x)?([0-9A-Fa-f]{4})$/) {
+       $res->{vendorid} = $2;
+       $res->{productid} = $4;
+    } elsif ($value =~ m/^(\d+)\-(\d+(\.\d+)*)$/) {
+       $res->{hostbus} = $1;
+       $res->{hostport} = $2;
+    } elsif ($value =~ m/^spice$/i) {
+       $res->{spice} = 1;
+    } else {
+       return undef;
     }
-    return undef if !$found;
 
     return $res;
 }
@@ -1972,13 +1980,13 @@ sub touch_config {
 }
 
 sub destroy_vm {
-    my ($storecfg, $vmid, $keep_empty_config) = @_;
+    my ($storecfg, $vmid, $keep_empty_config, $skiplock) = @_;
 
     my $conffile = config_file($vmid);
 
     my $conf = load_config($vmid);
 
-    check_lock($conf);
+    check_lock($conf) if !$skiplock;
 
     # only remove disks owned by this VM
     foreach_drive($conf, sub {
@@ -2236,22 +2244,14 @@ sub write_vm_config {
     return $raw;
 }
 
-sub update_config_nolock {
-    my ($vmid, $conf, $skiplock) = @_;
-
-    check_lock($conf) if !$skiplock;
+sub write_config {
+    my ($vmid, $conf) = @_;
 
     my $cfspath = cfs_config_path($vmid);
 
     PVE::Cluster::cfs_write_file($cfspath, $conf);
 }
 
-sub update_config {
-    my ($vmid, $conf, $skiplock) = @_;
-
-    lock_config($vmid, &update_config_nolock, $conf, $skiplock);
-}
-
 sub load_defaults {
 
     my $res = {};
@@ -2843,12 +2843,27 @@ sub config_to_command {
         my $use_usb2 = 0;
        for (my $i = 0; $i < $MAX_USB_DEVICES; $i++)  {
            next if !$conf->{"usb$i"};
+           my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format},$conf->{"usb$i"}) };
+           next if !$d || $d->{usb3}; # do not add usb2 controller if we have only usb3 devices
            $use_usb2 = 1;
        }
        # include usb device config
        push @$devices, '-readconfig', '/usr/share/qemu-server/pve-usb.cfg' if $use_usb2;
     }
 
+    # add usb3 controller if needed
+
+    my $use_usb3 = 0;
+    for (my $i = 0; $i < $MAX_USB_DEVICES; $i++)  {
+       next if !$conf->{"usb$i"};
+       my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format},$conf->{"usb$i"}) };
+       next if !$d || !$d->{usb3};
+       $use_usb3 = 1;
+    }
+
+    $pciaddr = print_pci_addr("xhci", $bridges);
+    push @$devices, '-device', "nec-usb-xhci,id=xhci$pciaddr" if $use_usb3;
+
     my $vga = $conf->{vga};
 
     my $qxlnum = vga_conf_has_spice($vga);
@@ -2925,16 +2940,27 @@ sub config_to_command {
 
     # usb devices
     for (my $i = 0; $i < $MAX_USB_DEVICES; $i++)  {
-       my $d = parse_usb_device($conf->{"usb$i"});
+       next if !$conf->{"usb$i"};
+       my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format},$conf->{"usb$i"}) };
        next if !$d;
-       if ($d->{vendorid} && $d->{productid}) {
-           push @$devices, '-device', "usb-host,vendorid=0x$d->{vendorid},productid=0x$d->{productid}";
-       } elsif (defined($d->{hostbus}) && defined($d->{hostport})) {
-           push @$devices, '-device', "usb-host,hostbus=$d->{hostbus},hostport=$d->{hostport}";
-       } elsif ($d->{spice}) {
-           # usb redir support for spice
-           push @$devices, '-chardev', "spicevmc,id=usbredirchardev$i,name=usbredir";
-           push @$devices, '-device', "usb-redir,chardev=usbredirchardev$i,id=usbredirdev$i,bus=ehci.0";
+
+       # if it is a usb3 device, attach it to the xhci controller, else omit the bus option
+       my $usbbus = '';
+       if (defined($d->{usb3}) && $d->{usb3}) {
+           $usbbus = ',bus=xhci.0';
+       }
+
+       if (defined($d->{host})) {
+           $d = parse_usb_device($d->{host});
+           if (defined($d->{vendorid}) && defined($d->{productid})) {
+               push @$devices, '-device', "usb-host$usbbus,vendorid=0x$d->{vendorid},productid=0x$d->{productid}";
+           } elsif (defined($d->{hostbus}) && defined($d->{hostport})) {
+               push @$devices, '-device', "usb-host$usbbus,hostbus=$d->{hostbus},hostport=$d->{hostport}";
+           } elsif (defined($d->{spice}) && $d->{spice}) {
+               # usb redir support for spice, currently no usb3
+               push @$devices, '-chardev', "spicevmc,id=usbredirchardev$i,name=usbredir";
+               push @$devices, '-device', "usb-redir,chardev=usbredirchardev$i,id=usbredirdev$i,bus=ehci.0";
+           }
        }
     }
 
@@ -3185,7 +3211,7 @@ sub config_to_command {
            #if dimm_memory is not aligned to dimm map
            if($current_size > $memory) {
                 $conf->{memory} = $current_size;
-                update_config_nolock($vmid, $conf, 1);
+                write_config($vmid, $conf);
            }
        });
     }
@@ -3842,7 +3868,7 @@ sub qemu_memory_hotplug {
                }
                #update conf after each succesful module hotplug
                $conf->{memory} = $current_size;
-               update_config_nolock($vmid, $conf, 1);
+               write_config($vmid, $conf);
        });
 
     } else {
@@ -3867,7 +3893,7 @@ sub qemu_memory_hotplug {
                $conf->{memory} = $current_size;
 
                eval { qemu_objectdel($vmid, "mem-$name"); };
-               update_config_nolock($vmid, $conf, 1);
+               write_config($vmid, $conf);
        });
     }
 }
@@ -4120,7 +4146,7 @@ sub vmconfig_hotplug_pending {
     }
 
     if ($changes) {
-       update_config_nolock($vmid, $conf, 1);
+       write_config($vmid, $conf);
        $conf = load_config($vmid); # update/reload
     }
 
@@ -4171,7 +4197,7 @@ sub vmconfig_hotplug_pending {
            # save new config if hotplug was successful
            delete $conf->{$opt};
            vmconfig_undelete_pending_option($conf, $opt);
-           update_config_nolock($vmid, $conf, 1);
+           write_config($vmid, $conf);
            $conf = load_config($vmid); # update/reload
        }
     }
@@ -4229,7 +4255,7 @@ sub vmconfig_hotplug_pending {
            # save new config if hotplug was successful
            $conf->{$opt} = $value;
            delete $conf->{pending}->{$opt};
-           update_config_nolock($vmid, $conf, 1);
+           write_config($vmid, $conf);
            $conf = load_config($vmid); # update/reload
        }
     }
@@ -4285,16 +4311,16 @@ sub vmconfig_apply_pending {
        $conf = load_config($vmid); # update/reload
        if (!defined($conf->{$opt})) {
            vmconfig_undelete_pending_option($conf, $opt);
-           update_config_nolock($vmid, $conf, 1);
+           write_config($vmid, $conf);
        } elsif (valid_drivename($opt)) {
            vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
            vmconfig_undelete_pending_option($conf, $opt);
            delete $conf->{$opt};
-           update_config_nolock($vmid, $conf, 1);
+           write_config($vmid, $conf);
        } else {
            vmconfig_undelete_pending_option($conf, $opt);
            delete $conf->{$opt};
-           update_config_nolock($vmid, $conf, 1);
+           write_config($vmid, $conf);
        }
     }
 
@@ -4314,7 +4340,7 @@ sub vmconfig_apply_pending {
        }
 
        delete $conf->{pending}->{$opt};
-       update_config_nolock($vmid, $conf, 1);
+       write_config($vmid, $conf);
     }
 }
 
@@ -4472,7 +4498,7 @@ sub vmconfig_update_disk {
 
     die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
     # hotplug new disks
-    PVE::Storage::activate_volumes($storecfg, [$drive->{file}]);
+    PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
     vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive);
 }
 
@@ -4857,10 +4883,8 @@ sub vm_destroy {
 
        my $conf = load_config($vmid);
 
-       check_lock($conf) if !$skiplock;
-
        if (!check_running($vmid)) {
-           destroy_vm($storecfg, $vmid);
+           destroy_vm($storecfg, $vmid, undef, $skiplock);
        } else {
            die "VM $vmid is running - destroy failed\n";
        }
@@ -5047,6 +5071,7 @@ sub print_pci_addr {
        'net29' => { bus => 1, addr => 24 },
        'net30' => { bus => 1, addr => 25 },
        'net31' => { bus => 1, addr => 26 },
+       'xhci' => { bus => 1, addr => 27 },
        'virtio6' => { bus => 2, addr => 1 },
        'virtio7' => { bus => 2, addr => 2 },
        'virtio8' => { bus => 2, addr => 3 },
@@ -5236,10 +5261,10 @@ sub restore_update_config_line {
     } elsif ($line =~ m/^((ide|scsi|virtio|sata)\d+):\s*(\S+)\s*$/) {
        my $virtdev = $1;
        my $value = $3;
-       if ($line =~ m/backup=no/) {
+       my $di = parse_drive($virtdev, $value);
+       if (defined($di->{backup}) && !$di->{backup}) {
            print $outfd "#$line";
-       } elsif ($virtdev && $map->{$virtdev}) {
-           my $di = parse_drive($virtdev, $value);
+       } elsif ($map->{$virtdev}) {
            delete $di->{format}; # format can change on restore
            $di->{file} = $map->{$virtdev};
            $value = print_drive($vmid, $di);
@@ -5395,7 +5420,7 @@ sub rescan {
 
        my $changes = update_disksize($vmid, $conf, $vm_volids);
 
-       update_config_nolock($vmid, $conf, 1) if $changes;
+       write_config($vmid, $conf) if $changes;
     };
 
     if (defined($vmid)) {
@@ -5920,8 +5945,7 @@ my $snapshot_prepare = sub {
        # always overwrite machine if we save vmstate. This makes sure we
        # can restore it later using correct machine type
        $snap->{machine} = get_current_qemu_machine($vmid) if $snap->{vmstate};
-
-       update_config_nolock($vmid, $conf, 1);
+       write_config($vmid, $conf);
     };
 
     lock_config($vmid, $updatefn);
@@ -5957,7 +5981,7 @@ my $snapshot_commit = sub {
 
        $newconf->{parent} = $snapname;
 
-       update_config_nolock($vmid, $newconf, 1);
+       write_config($vmid, $newconf);
     };
 
     lock_config($vmid, $updatefn);
@@ -6036,7 +6060,7 @@ sub snapshot_rollback {
            delete $conf->{machine} if $snap->{vmstate} && !$has_machine_config;
        }
 
-       update_config_nolock($vmid, $conf, 1);
+       write_config($vmid, $conf);
 
        if (!$prepare && $snap->{vmstate}) {
            my $statefile = PVE::Storage::path($storecfg, $snap->{vmstate});
@@ -6244,7 +6268,7 @@ sub snapshot_delete {
            }
        }
 
-       update_config_nolock($vmid, $conf, 1);
+       write_config($vmid, $conf);
     };
 
     lock_config($vmid, $updatefn);
@@ -6322,7 +6346,7 @@ sub template_create {
        my $voliddst = PVE::Storage::vdisk_create_base($storecfg, $volid);
        $drive->{file} = $voliddst;
        $conf->{$ds} = print_drive($vmid, $drive);
-       update_config_nolock($vmid, $conf, 1);
+       write_config($vmid, $conf);
     });
 }