]> git.proxmox.com Git - qemu-server.git/blobdiff - PVE/QemuServer.pm
snapshot_delete: reorder parent "connection" after prepare
[qemu-server.git] / PVE / QemuServer.pm
index 597d01358941f43f4a86f35d08da1312d756695b..ed46df125403579b6794de71d687f6e2ab732d05 100644 (file)
@@ -22,7 +22,7 @@ use PVE::SafeSyslog;
 use Storable qw(dclone);
 use PVE::Exception qw(raise raise_param_exc);
 use PVE::Storage;
-use PVE::Tools qw(run_command lock_file lock_file_full file_read_firstline);
+use PVE::Tools qw(run_command lock_file lock_file_full file_read_firstline dir_glob_foreach);
 use PVE::JSONSchema qw(get_standard_option);
 use PVE::Cluster qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file);
 use PVE::INotify;
@@ -437,6 +437,13 @@ EODESCR
        maxLength => 40,
        optional => 1,
     },
+    smbios1 => {
+       description => "Specify SMBIOS type 1 fields.",
+       type => 'string', format => 'pve-qm-smbios1',
+       typetext => "[manufacturer=str][,product=str][,version=str][,serial=str] [,uuid=uuid][,sku=str][,family=str]",
+       maxLength => 256,
+       optional => 1,
+    },
 };
 
 # what about other qemu settings ?
@@ -1267,9 +1274,15 @@ sub parse_hostpci {
     my $res = {};
     foreach my $kv (@list) {
 
-       if ($kv =~ m/^(host=)?([a-f0-9]{2}:[a-f0-9]{2}\.[a-f0-9])$/) {
+       if ($kv =~ m/^(host=)?([a-f0-9]{2}:[a-f0-9]{2})(\.([a-f0-9]))?$/) {
            $found = 1;
-           $res->{pciid} = $2;
+           if(defined($4)){
+               push @{$res->{pciid}}, { id => $2 , function => $4};
+
+           }else{
+               my $pcidevices = lspci($2);
+               $res->{pciid} = $pcidevices->{$2};
+           }
        } elsif ($kv =~ m/^driver=(kvm|vfio)$/) {
            $res->{driver} = $1;
        } elsif ($kv =~ m/^rombar=(on|off)$/) {
@@ -1366,6 +1379,45 @@ sub add_unused_volume {
     return $key;
 }
 
+my $valid_smbios1_options = {
+    manufacturer => '\S+',
+    product => '\S+',
+    version => '\S+',
+    serial => '\S+',
+    uuid => '[a-fA-F0-9]{8}(?:-[a-fA-F0-9]{4}){3}-[a-fA-F0-9]{12}',
+    sku => '\S+',
+    family => '\S+',
+};
+
+# smbios: [manufacturer=str][,product=str][,version=str][,serial=str][,uuid=uuid][,sku=str][,family=str]
+sub parse_smbios1 {
+    my ($data) = @_;
+
+    my $res = {};
+
+    foreach my $kvp (split(/,/, $data)) {
+       return undef if $kvp !~ m/^(\S+)=(.+)$/;
+       my ($k, $v) = split(/=/, $kvp);
+       return undef if !defined($k) || !defined($v);
+       return undef if !$valid_smbios1_options->{$k};
+       return undef if $v !~ m/^$valid_smbios1_options->{$k}$/;
+       $res->{$k} = $v;
+    }
+
+    return $res;
+}
+
+PVE::JSONSchema::register_format('pve-qm-smbios1', \&verify_smbios1);
+sub verify_smbios1 {
+    my ($value, $noerr) = @_;
+
+    return $value if parse_smbios1($value);
+
+    return undef if $noerr;
+
+    die "unable to parse smbios (type 1) options\n";
+}
+
 PVE::JSONSchema::register_format('pve-qm-bootdisk', \&verify_bootdisk);
 sub verify_bootdisk {
     my ($value, $noerr) = @_;
@@ -2369,6 +2421,10 @@ sub config_to_command {
 
     push @$cmd, '-daemonize';
 
+    if ($conf->{smbios1}) {
+       push @$cmd, '-smbios', "type=1,$conf->{smbios1}";
+    }
+
     if ($q35) {
        # the q35 chipset support native usb2, so we enable usb controller 
        # by default for this machine type
@@ -2430,9 +2486,26 @@ sub config_to_command {
        my $driver = $d->{driver} && $d->{driver} eq 'vfio' ? "vfio-pci" : "pci-assign";
        my $xvga = $d->{'x-vga'} && $d->{'x-vga'} eq 'on' ? ",x-vga=on" : "";
        $driver = "vfio-pci" if $xvga ne '';
+       my $pcidevices = $d->{pciid};
+       my $multifunction = 1 if @$pcidevices > 1;
+
+       my $j=0;
+        foreach my $pcidevice (@$pcidevices) {
 
-       push @$devices, '-device', "$driver,host=$d->{pciid},id=hostpci$i$pciaddr$rombar$xvga";
+           my $id = "hostpci$i";
+           $id .= ".$j" if $multifunction;
+           my $addr = $pciaddr;
+           $addr .= ".$j" if $multifunction;
+           my $devicestr = "$driver,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
 
+           if($j == 0){
+               $devicestr .= "$rombar$xvga";
+               $devicestr .= ",multifunction=on" if $multifunction;
+           }
+
+           push @$devices, '-device', $devicestr;
+           $j++;
+       }
     }
 
     # usb devices
@@ -3283,17 +3356,22 @@ sub vm_start {
         for (my $i = 0; $i < $MAX_HOSTPCI_DEVICES; $i++)  {
           my $d = parse_hostpci($conf->{"hostpci$i"});
           next if !$d;
-          my $info = pci_device_info("0000:$d->{pciid}");
-          die "IOMMU not present\n" if !check_iommu_support();
-          die "no pci device info for device '$d->{pciid}'\n" if !$info;
+         my $pcidevices = $d->{pciid};
+         foreach my $pcidevice (@$pcidevices) {
+               my $pciid = $pcidevice->{id}.".".$pcidevice->{function};
+
+               my $info = pci_device_info("0000:$pciid");
+               die "IOMMU not present\n" if !check_iommu_support();
+               die "no pci device info for device '$pciid'\n" if !$info;
 
-          if ($d->{driver} && $d->{driver} eq "vfio") {
-              die "can't unbind/bind pci group to vfio '$d->{pciid}'\n" if !pci_dev_group_bind_to_vfio($d->{pciid});
-          } else {
-              die "can't unbind/bind to stub pci device '$d->{pciid}'\n" if !pci_dev_bind_to_stub($info);
-          }
+               if ($d->{driver} && $d->{driver} eq "vfio") {
+                   die "can't unbind/bind pci group to vfio '$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
+               } else {
+                   die "can't unbind/bind to stub pci device '$pciid'\n" if !pci_dev_bind_to_stub($info);
+               }
 
-          die "can't reset pci device '$d->{pciid}'\n" if !pci_dev_reset($info);
+               die "can't reset pci device '$pciid'\n" if !pci_dev_reset($info);
+         }
         }
 
        PVE::Storage::activate_volumes($storecfg, $vollist);
@@ -4857,10 +4935,12 @@ sub snapshot_delete {
        die "snapshot '$snapname' does not exist\n" if !defined($snap);
 
        # remove parent refs
-       &$unlink_parent($conf, $snap->{parent});
-       foreach my $sn (keys %{$conf->{snapshots}}) {
-           next if $sn eq $snapname;
-           &$unlink_parent($conf->{snapshots}->{$sn}, $snap->{parent});
+       if (!$prepare) {
+           &$unlink_parent($conf, $snap->{parent});
+           foreach my $sn (keys %{$conf->{snapshots}}) {
+               next if $sn eq $snapname;
+               &$unlink_parent($conf->{snapshots}->{$sn}, $snap->{parent});
+           }
        }
 
        if ($remove_drive) {
@@ -5112,7 +5192,7 @@ sub clone_disk {
 
     if (!$full) {
        print "create linked clone of drive $drivename ($drive->{file})\n";
-       $newvolid = PVE::Storage::vdisk_clone($storecfg,  $drive->{file}, $newvmid);
+       $newvolid = PVE::Storage::vdisk_clone($storecfg,  $drive->{file}, $newvmid, $snapname);
        push @$newvollist, $newvolid;
     } else {
        my ($storeid, $volname) = PVE::Storage::parse_volume_id($drive->{file});
@@ -5167,4 +5247,17 @@ sub get_current_qemu_machine {
     return $current || $default || 'pc';
 }
 
+sub lspci {
+
+    my $devices = {};
+
+    dir_glob_foreach("$pcisysfs/devices", '[a-f0-9]{4}:([a-f0-9]{2}:[a-f0-9]{2})\.([0-9])', sub {
+            my (undef, $id, $function) = @_;
+           my $res = { id => $id, function => $function};
+           push @{$devices->{$id}}, $res;
+    });
+
+    return $devices;
+}
+
 1;