Blob Blame History Raw
diff -up libpciaccess-20071031/src/linux_sysfs.c.cache libpciaccess-20071031/src/linux_sysfs.c
--- libpciaccess-20071031/src/linux_sysfs.c.cache	2007-10-23 09:19:36.000000000 -0400
+++ libpciaccess-20071031/src/linux_sysfs.c	2008-01-22 19:23:12.000000000 -0500
@@ -55,6 +55,8 @@
 #include "pciaccess_private.h"
 #include "linux_devmem.h"
 
+static void pci_device_linux_sysfs_destroy( void );
+
 static int pci_device_linux_sysfs_read_rom( struct pci_device * dev,
     void * buffer );
 
@@ -74,7 +76,7 @@
     pciaddr_t * bytes_wrtten );
 
 static const struct pci_system_methods linux_sysfs_methods = {
-    .destroy = NULL,
+    .destroy = pci_device_linux_sysfs_destroy,
     .destroy_device = NULL,
     .read_rom = pci_device_linux_sysfs_read_rom,
     .probe = pci_device_linux_sysfs_probe,
@@ -362,6 +364,53 @@
     return err;
 }
 
+static struct pci_device *last_config_dev = NULL;
+static int config_fd = -1;
+
+static void
+pci_device_linux_sysfs_destroy( void )
+{
+    if (config_fd != -1)
+	close( config_fd );
+}
+
+static int
+open_config_fd( struct pci_device * dev, int flags )
+{
+    int fd;
+    char name[256];
+
+    /* Each device has a directory under sysfs.  Within that directory there
+     * is a file named "config".  This file used to access the PCI config
+     * space.  It is used here to obtain most of the information about the
+     * device.
+     */
+
+    if ( last_config_dev != dev ) {
+	if ( config_fd != -1 ) {
+	    close( config_fd );
+	    last_config_dev = NULL;
+	}
+
+	snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/config",
+		  SYS_BUS_PCI,
+	          dev->domain,
+	          dev->bus,
+	          dev->dev,
+	          dev->func );
+
+	fd = open( name, flags );
+	if ( fd == -1 ) {
+	    return -1;
+	}
+	config_fd = fd;
+	last_config_dev = dev;
+    } else {
+	fd = config_fd;
+    }
+
+    return fd;
+}
 
 static int
 pci_device_linux_sysfs_read( struct pci_device * dev, void * data,
@@ -378,23 +427,9 @@
 	*bytes_read = 0;
     }
 
-    /* Each device has a directory under sysfs.  Within that directory there
-     * is a file named "config".  This file used to access the PCI config
-     * space.  It is used here to obtain most of the information about the
-     * device.
-     */
-    snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/config",
-	      SYS_BUS_PCI,
-	      dev->domain,
-	      dev->bus,
-	      dev->dev,
-	      dev->func );
-
-    fd = open( name, O_RDONLY );
-    if ( fd == -1 ) {
+    fd = open_config_fd( dev, O_RDONLY );
+    if ( fd == -1 )
 	return errno;
-    }
-
 
     while ( temp_size > 0 ) {
 	const ssize_t bytes = pread64( fd, data_bytes, temp_size, offset );
@@ -416,7 +451,6 @@
 	*bytes_read = size - temp_size;
     }
 
-    close( fd );
     return err;
 }
 
@@ -436,23 +470,9 @@
 	*bytes_written = 0;
     }
 
-    /* Each device has a directory under sysfs.  Within that directory there
-     * is a file named "config".  This file used to access the PCI config
-     * space.  It is used here to obtain most of the information about the
-     * device.
-     */
-    snprintf( name, 255, "%s/%04x:%02x:%02x.%1u/config",
-	      SYS_BUS_PCI,
-	      dev->domain,
-	      dev->bus,
-	      dev->dev,
-	      dev->func );
-
-    fd = open( name, O_WRONLY );
-    if ( fd == -1 ) {
+    fd = open_config_fd( dev, O_WRONLY );
+    if ( fd == -1 )
 	return errno;
-    }
-
 
     while ( temp_size > 0 ) {
 	const ssize_t bytes = pwrite64( fd, data_bytes, temp_size, offset );
@@ -474,7 +494,6 @@
 	*bytes_written = size - temp_size;
     }
 
-    close( fd );
     return err;
 }