[pve-devel] [PATCH qemu-server 1/2] move pci related subs to QemuServer/PCI.pm

Thomas Lamprecht t.lamprecht at proxmox.com
Wed Nov 14 07:29:14 CET 2018


On 11/13/18 3:18 PM, Dominik Csapak wrote:
> and refactor the pci regex in lspci and pci_device_info

do this in two steps please,
1. move only
2. refactor

way easier to see what's going on... and you need to send a v2 anyway,
as you notified me off-list, so this could be included there.

> 
> Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
> ---
>  PVE/QemuServer.pm     | 157 +++-----------------------------------------------
>  PVE/QemuServer/PCI.pm | 148 +++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 155 insertions(+), 150 deletions(-)
> 
> diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
> index bf1a1fb..71ef81c 100644
> --- a/PVE/QemuServer.pm
> +++ b/PVE/QemuServer.pm
> @@ -2078,7 +2078,7 @@ sub parse_hostpci {
>  	    if (defined($2)) {
>  		push @{$res->{pciid}}, { id => $1, function => $2 };
>  	    } else {
> -		my $pcidevices = lspci($1);
> +		my $pcidevices = PVE::QemuServer::PCI::lspci($1);
>  		$res->{pciid} = $pcidevices->{$1};
>  	    }
>  	} else {
> @@ -2427,15 +2427,6 @@ sub check_type {
>      }
>  }
>  
> -sub check_iommu_support{
> -    #fixme : need to check IOMMU support
> -    #http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM
> -
> -    my $iommu=1;
> -    return $iommu;
> -
> -}
> -
>  sub touch_config {
>      my ($vmid) = @_;
>  
> @@ -5033,11 +5024,13 @@ sub vm_start {
>  	  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();
> +		my $info = PVE::QemuServer::PCI::pci_device_info("0000:$pciid");
> +		die "IOMMU not present\n" if !PVE::QemuServer::PCI::check_iommu_support();
>  		die "no pci device info for device '$pciid'\n" if !$info;
> -		die "can't unbind/bind pci group to vfio '$pciid'\n" if !pci_dev_group_bind_to_vfio($pciid);
> -		die "can't reset pci device '$pciid'\n" if $info->{has_fl_reset} and !pci_dev_reset($info);
> +		die "can't unbind/bind pci group to vfio '$pciid'\n"
> +		    if !PVE::QemuServer::PCI::pci_dev_group_bind_to_vfio($pciid);
> +		die "can't reset pci device '$pciid'\n"
> +		    if $info->{has_fl_reset} and !PVE::QemuServer::PCI::pci_dev_reset($info);
>  	  }
>          }
>  
> @@ -5442,123 +5435,6 @@ sub vm_destroy {
>      });
>  }
>  
> -# pci helpers
> -
> -sub file_write {
> -    my ($filename, $buf) = @_;
> -
> -    my $fh = IO::File->new($filename, "w");
> -    return undef if !$fh;
> -
> -    my $res = print $fh $buf;
> -
> -    $fh->close();
> -
> -    return $res;
> -}
> -
> -sub pci_device_info {
> -    my ($name) = @_;
> -
> -    my $res;
> -
> -    return undef if $name !~ m/^([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\.([a-f0-9])$/;
> -    my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4);
> -
> -    my $irq = file_read_firstline("$pcisysfs/devices/$name/irq");
> -    return undef if !defined($irq) || $irq !~ m/^\d+$/;
> -
> -    my $vendor = file_read_firstline("$pcisysfs/devices/$name/vendor");
> -    return undef if !defined($vendor) || $vendor !~ s/^0x//;
> -
> -    my $product = file_read_firstline("$pcisysfs/devices/$name/device");
> -    return undef if !defined($product) || $product !~ s/^0x//;
> -
> -    $res = {
> -	name => $name,
> -	vendor => $vendor,
> -	product => $product,
> -	domain => $domain,
> -	bus => $bus,
> -	slot => $slot,
> -	func => $func,
> -	irq => $irq,
> -	has_fl_reset => -f "$pcisysfs/devices/$name/reset" || 0,
> -    };
> -
> -    return $res;
> -}
> -
> -sub pci_dev_reset {
> -    my ($dev) = @_;
> -
> -    my $name = $dev->{name};
> -
> -    my $fn = "$pcisysfs/devices/$name/reset";
> -
> -    return file_write($fn, "1");
> -}
> -
> -sub pci_dev_bind_to_vfio {
> -    my ($dev) = @_;
> -
> -    my $name = $dev->{name};
> -
> -    my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
> -
> -    if (!-d $vfio_basedir) {
> -	system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
> -    }
> -    die "Cannot find vfio-pci module!\n" if !-d $vfio_basedir;
> -
> -    my $testdir = "$vfio_basedir/$name";
> -    return 1 if -d $testdir;
> -
> -    my $data = "$dev->{vendor} $dev->{product}";
> -    return undef if !file_write("$vfio_basedir/new_id", $data);
> -
> -    my $fn = "$pcisysfs/devices/$name/driver/unbind";
> -    if (!file_write($fn, $name)) {
> -	return undef if -f $fn;
> -    }
> -
> -    $fn = "$vfio_basedir/bind";
> -    if (! -d $testdir) {
> -	return undef if !file_write($fn, $name);
> -    }
> -
> -    return -d $testdir;
> -}
> -
> -sub pci_dev_group_bind_to_vfio {
> -    my ($pciid) = @_;
> -
> -    my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
> -
> -    if (!-d $vfio_basedir) {
> -	system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
> -    }
> -    die "Cannot find vfio-pci module!\n" if !-d $vfio_basedir;
> -
> -    # get IOMMU group devices
> -    opendir(my $D, "$pcisysfs/devices/0000:$pciid/iommu_group/devices/") || die "Cannot open iommu_group: $!\n";
> -      my @devs = grep /^0000:/, readdir($D);
> -    closedir($D);
> -
> -    foreach my $pciid (@devs) {
> -	$pciid =~ m/^([:\.\da-f]+)$/ or die "PCI ID $pciid not valid!\n";
> -
> -        # pci bridges, switches or root ports are not supported
> -        # they have a pci_bus subdirectory so skip them
> -        next if (-e "$pcisysfs/devices/$pciid/pci_bus");
> -
> -	my $info = pci_device_info($1);
> -	pci_dev_bind_to_vfio($info) || die "Cannot bind $pciid to vfio\n";
> -    }
> -
> -    return 1;
> -}
> -
>  # vzdump restore implementaion
>  
>  sub tar_archive_read_firstfile {
> @@ -6761,25 +6637,6 @@ sub create_efidisk {
>      return ($volid, $vars_size);
>  }
>  
> -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;
> -    });
> -
> -    # Entries should be sorted by functions.
> -    foreach my $id (keys %$devices) {
> -	my $dev = $devices->{$id};
> -	$devices->{$id} = [ sort { $a->{function} <=> $b->{function} } @$dev ];
> -    }
> -
> -    return $devices;
> -}
> -
>  sub vm_iothreads_list {
>      my ($vmid) = @_;
>  
> diff --git a/PVE/QemuServer/PCI.pm b/PVE/QemuServer/PCI.pm
> index 5ddda4f..ab534f4 100644
> --- a/PVE/QemuServer/PCI.pm
> +++ b/PVE/QemuServer/PCI.pm
> @@ -1,5 +1,7 @@
>  package PVE::QemuServer::PCI;
>  
> +use PVE::Tools qw(file_read_firstline dir_glob_foreach);
> +
>  use base 'Exporter';
>  
>  our @EXPORT_OK = qw(
> @@ -145,3 +147,149 @@ sub print_pcie_addr {
>      return $res;
>  
>  }
> +
> +my $pcisysfs = "/sys/bus/pci";
> +my $pciregex = "([a-fA-F0-9]{4}):([a-fA-F0-9]{2}):([a-fA-F0-9]{2})\.([a-fA-F0-9])";
> +
> +sub lspci {
> +
> +    my $devices = {};
> +
> +    dir_glob_foreach("$pcisysfs/devices", '${pciregex}', sub {
> +            my (undef, $domain, $bus, $slot, $function) = @_;
> +	    my $id = "$bus:$slot";
> +	    my $res = { id => $id, function => $function };
> +	    push @{$devices->{$id}}, $res;
> +    });
> +
> +    # Entries should be sorted by functions.
> +    foreach my $id (keys %$devices) {
> +	my $dev = $devices->{$id};
> +	$devices->{$id} = [ sort { $a->{function} <=> $b->{function} } @$dev ];
> +    }
> +
> +    return $devices;
> +}
> +
> +
> +sub check_iommu_support{
> +    my $entry = PVE::Tools::dir_glob_regex('/sys/class/iommu/', '[^\.].*');
> +    return defined($entry);
> +}
> +
> +sub file_write {
> +    my ($filename, $buf) = @_;
> +
> +    my $fh = IO::File->new($filename, "w");
> +    return undef if !$fh;
> +
> +    my $res = print $fh $buf;
> +
> +    $fh->close();
> +
> +    return $res;
> +}
> +
> +sub pci_device_info {
> +    my ($name) = @_;
> +
> +    my $res;
> +
> +    return undef if $name !~ m/^${pciregex}$/;
> +    my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4);
> +
> +    my $irq = file_read_firstline("$pcisysfs/devices/$name/irq");
> +    return undef if !defined($irq) || $irq !~ m/^\d+$/;
> +
> +    my $vendor = file_read_firstline("$pcisysfs/devices/$name/vendor");
> +    return undef if !defined($vendor) || $vendor !~ s/^0x//;
> +
> +    my $product = file_read_firstline("$pcisysfs/devices/$name/device");
> +    return undef if !defined($product) || $product !~ s/^0x//;
> +
> +    $res = {
> +	name => $name,
> +	vendor => $vendor,
> +	product => $product,
> +	domain => $domain,
> +	bus => $bus,
> +	slot => $slot,
> +	func => $func,
> +	irq => $irq,
> +	has_fl_reset => -f "$pcisysfs/devices/$name/reset" || 0,
> +    };
> +
> +    return $res;
> +}
> +
> +sub pci_dev_reset {
> +    my ($dev) = @_;
> +
> +    my $name = $dev->{name};
> +
> +    my $fn = "$pcisysfs/devices/$name/reset";
> +
> +    return file_write($fn, "1");
> +}
> +
> +sub pci_dev_bind_to_vfio {
> +    my ($dev) = @_;
> +
> +    my $name = $dev->{name};
> +
> +    my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
> +
> +    if (!-d $vfio_basedir) {
> +	system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
> +    }
> +    die "Cannot find vfio-pci module!\n" if !-d $vfio_basedir;
> +
> +    my $testdir = "$vfio_basedir/$name";
> +    return 1 if -d $testdir;
> +
> +    my $data = "$dev->{vendor} $dev->{product}";
> +    return undef if !file_write("$vfio_basedir/new_id", $data);
> +
> +    my $fn = "$pcisysfs/devices/$name/driver/unbind";
> +    if (!file_write($fn, $name)) {
> +	return undef if -f $fn;
> +    }
> +
> +    $fn = "$vfio_basedir/bind";
> +    if (! -d $testdir) {
> +	return undef if !file_write($fn, $name);
> +    }
> +
> +    return -d $testdir;
> +}
> +
> +sub pci_dev_group_bind_to_vfio {
> +    my ($pciid) = @_;
> +
> +    my $vfio_basedir = "$pcisysfs/drivers/vfio-pci";
> +
> +    if (!-d $vfio_basedir) {
> +	system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null");
> +    }
> +    die "Cannot find vfio-pci module!\n" if !-d $vfio_basedir;
> +
> +    # get IOMMU group devices
> +    opendir(my $D, "$pcisysfs/devices/0000:$pciid/iommu_group/devices/") || die "Cannot open iommu_group: $!\n";
> +      my @devs = grep /^0000:/, readdir($D);
> +    closedir($D);
> +
> +    foreach my $pciid (@devs) {
> +	$pciid =~ m/^([:\.\da-f]+)$/ or die "PCI ID $pciid not valid!\n";
> +
> +        # pci bridges, switches or root ports are not supported
> +        # they have a pci_bus subdirectory so skip them
> +        next if (-e "$pcisysfs/devices/$pciid/pci_bus");
> +
> +	my $info = pci_device_info($1);
> +	pci_dev_bind_to_vfio($info) || die "Cannot bind $pciid to vfio\n";
> +    }
> +
> +    return 1;
> +}
> +
> +1;
> 





More information about the pve-devel mailing list