Skip to content

Commit 24de09c

Browse files
Valentine Sinitsyngregkh
authored andcommitted
PCI: Implement custom llseek for sysfs resource entries
Since commit 636b21b ("PCI: Revoke mappings like devmem"), mmappable sysfs entries have started to receive their f_mapping from the iomem pseudo filesystem, so that CONFIG_IO_STRICT_DEVMEM is honored in sysfs (and procfs) as well as in /dev/[k]mem. This resulted in a userspace-visible regression: 1. Open a sysfs PCI resource file (eg. /sys/bus/pci/devices/*/resource0) 2. Use lseek(fd, 0, SEEK_END) to determine its size Expected result: a PCI region size is returned. Actual result: 0 is returned. The reason is that PCI resource files residing in sysfs use generic_file_llseek(), which relies on f_mapping->host inode to get the file size. As f_mapping is now redefined, f_mapping->host points to an anonymous zero-sized iomem_inode which has nothing to do with sysfs file in question. Implement a custom llseek method for sysfs PCI resources, which is almost the same as proc_bus_pci_lseek() used for procfs entries. This makes sysfs and procfs entries consistent with regards to seeking, but also introduces userspace-visible changes to seeking PCI resources in sysfs: - SEEK_DATA and SEEK_HOLE are no longer supported; - Seeking past the end of the file is prohibited while previously offsets up to MAX_NON_LFS were accepted (reading from these offsets was always invalid). Signed-off-by: Valentine Sinitsyn <[email protected]> Acked-by: Bjorn Helgaas <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 0fedefd commit 24de09c

File tree

1 file changed

+25
-1
lines changed

1 file changed

+25
-1
lines changed

drivers/pci/pci-sysfs.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,19 @@ static const struct attribute_group pci_dev_config_attr_group = {
835835
.is_bin_visible = pci_dev_config_attr_is_visible,
836836
};
837837

838+
/*
839+
* llseek operation for mmappable PCI resources.
840+
* May be left unused if the arch doesn't provide them.
841+
*/
842+
static __maybe_unused loff_t
843+
pci_llseek_resource(struct file *filep,
844+
struct kobject *kobj __always_unused,
845+
struct bin_attribute *attr,
846+
loff_t offset, int whence)
847+
{
848+
return fixed_size_llseek(filep, offset, whence, attr->size);
849+
}
850+
838851
#ifdef HAVE_PCI_LEGACY
839852
/**
840853
* pci_read_legacy_io - read byte(s) from legacy I/O port space
@@ -967,6 +980,8 @@ void pci_create_legacy_files(struct pci_bus *b)
967980
b->legacy_io->attr.mode = 0600;
968981
b->legacy_io->read = pci_read_legacy_io;
969982
b->legacy_io->write = pci_write_legacy_io;
983+
/* See pci_create_attr() for motivation */
984+
b->legacy_io->llseek = pci_llseek_resource;
970985
b->legacy_io->mmap = pci_mmap_legacy_io;
971986
b->legacy_io->f_mapping = iomem_get_mapping;
972987
pci_adjust_legacy_attr(b, pci_mmap_io);
@@ -981,6 +996,8 @@ void pci_create_legacy_files(struct pci_bus *b)
981996
b->legacy_mem->size = 1024*1024;
982997
b->legacy_mem->attr.mode = 0600;
983998
b->legacy_mem->mmap = pci_mmap_legacy_mem;
999+
/* See pci_create_attr() for motivation */
1000+
b->legacy_mem->llseek = pci_llseek_resource;
9841001
b->legacy_mem->f_mapping = iomem_get_mapping;
9851002
pci_adjust_legacy_attr(b, pci_mmap_mem);
9861003
error = device_create_bin_file(&b->dev, b->legacy_mem);
@@ -1199,8 +1216,15 @@ static int pci_create_attr(struct pci_dev *pdev, int num, int write_combine)
11991216
res_attr->mmap = pci_mmap_resource_uc;
12001217
}
12011218
}
1202-
if (res_attr->mmap)
1219+
if (res_attr->mmap) {
12031220
res_attr->f_mapping = iomem_get_mapping;
1221+
/*
1222+
* generic_file_llseek() consults f_mapping->host to determine
1223+
* the file size. As iomem_inode knows nothing about the
1224+
* attribute, it's not going to work, so override it as well.
1225+
*/
1226+
res_attr->llseek = pci_llseek_resource;
1227+
}
12041228
res_attr->attr.name = res_attr_name;
12051229
res_attr->attr.mode = 0600;
12061230
res_attr->size = pci_resource_len(pdev, num);

0 commit comments

Comments
 (0)