diff options
author | Eric Anholt <eric@anholt.net> | 2008-06-05 11:39:06 -0700 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2008-06-05 11:39:06 -0700 |
commit | e3adc06b8b8214478aa1d3e85fd5f83b79d039b4 (patch) | |
tree | 9d429cd9ac8c60346b6b4e5f845119a309643c68 /src | |
parent | 4586bb6766983d040bff38b43dc458c47e0ca21f (diff) | |
download | libpciaccess-e3adc06b8b8214478aa1d3e85fd5f83b79d039b4.tar.gz libpciaccess-e3adc06b8b8214478aa1d3e85fd5f83b79d039b4.tar.bz2 libpciaccess-e3adc06b8b8214478aa1d3e85fd5f83b79d039b4.zip |
Catch and recover from yet another linux kernel bug in mprotect.
Diffstat (limited to 'src')
-rw-r--r-- | src/linux_sysfs.c | 25 |
1 files changed, 20 insertions, 5 deletions
diff --git a/src/linux_sysfs.c b/src/linux_sysfs.c index 9e53fac..b1d196c 100644 --- a/src/linux_sysfs.c +++ b/src/linux_sysfs.c @@ -537,12 +537,11 @@ pci_device_linux_sysfs_map_range(struct pci_device *dev, map->memory = mmap(NULL, map->size, prot, MAP_SHARED, fd, offset); if (map->memory == MAP_FAILED) { - err = errno; map->memory = NULL; + close(fd); + return errno; } - close(fd); - #ifdef HAVE_MTRR if ((map->flags & PCI_DEV_MAP_FLAG_CACHABLE) != 0) { sentry.type = MTRR_TYPE_WRBACK; @@ -562,11 +561,27 @@ pci_device_linux_sysfs_map_range(struct pci_device *dev, } /* KLUDGE ALERT -- rewrite the PTEs to turn off the CD and WT bits */ mprotect (map->memory, map->size, PROT_NONE); - mprotect (map->memory, map->size, PROT_READ|PROT_WRITE); + err = mprotect (map->memory, map->size, PROT_READ|PROT_WRITE); + + if (err != 0) { + fprintf(stderr, "mprotect(PROT_READ | PROT_WRITE) failed: %s\n", + strerror(errno)); + fprintf(stderr, "remapping without mprotect performace kludge.\n"); + + munmap(map->memory, map->size); + map->memory = mmap(NULL, map->size, prot, MAP_SHARED, fd, offset); + if (map->memory == MAP_FAILED) { + map->memory = NULL; + close(fd); + return errno; + } + } } #endif - return err; + close(fd); + + return 0; } /** |