[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