Both legacy and resource attributes set .f_mapping = iomem_get_mapping,
so the default generic_file_llseek() would consult iomem_inode for the
file size, which knows nothing about the attribute.  That is why custom
llseek callbacks exist.

Currently, the legacy and resource attributes have .size set at creation
time, as such, using the attr->size is sufficient.  However, the upcoming
static resource attributes will have .size == 0 set, since they are const,
and the .bin_size callback will be used to provide the real size to kernfs
instead.

The legacy attributes operate on a struct pci_bus, not struct pci_dev,
so calling to_pci_dev() on them would be invalid.

Thus, split pci_llseek_resource() into two functions:

  - pci_llseek_resource(), which derives the file size from the BAR
    using pci_resource_len().

  - pci_llseek_resource_legacy(), which uses attr->size directly.

Update the dynamic legacy attribute creation to use the new
pci_llseek_resource_legacy() callback.

The original pci_llseek_resource() was added in commit 24de09c16f97
("PCI: Implement custom llseek for sysfs resource entries").

Tested-by: Shivaprasad G Bhat <[email protected]>
Signed-off-by: Krzysztof Wilczyński <[email protected]>
---
 drivers/pci/pci-sysfs.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 2e4e226e78d4..2280b7edb41f 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -881,13 +881,26 @@ static const struct attribute_group 
pci_dev_config_attr_group = {
  * llseek operation for mmappable PCI resources.
  * May be left unused if the arch doesn't provide them.
  */
+static __maybe_unused loff_t
+pci_llseek_resource_legacy(struct file *filep,
+                          struct kobject *kobj __always_unused,
+                          const struct bin_attribute *attr,
+                          loff_t offset, int whence)
+{
+       return fixed_size_llseek(filep, offset, whence, attr->size);
+}
+
 static __maybe_unused loff_t
 pci_llseek_resource(struct file *filep,
-                   struct kobject *kobj __always_unused,
+                   struct kobject *kobj,
                    const struct bin_attribute *attr,
                    loff_t offset, int whence)
 {
-       return fixed_size_llseek(filep, offset, whence, attr->size);
+       struct pci_dev *pdev = to_pci_dev(kobj_to_dev(kobj));
+       int bar = (unsigned long)attr->private;
+
+       return fixed_size_llseek(filep, offset, whence,
+                                pci_resource_len(pdev, bar));
 }
 
 #ifdef HAVE_PCI_LEGACY
@@ -1022,7 +1035,7 @@ void pci_create_legacy_files(struct pci_bus *b)
        b->legacy_io->read = pci_read_legacy_io;
        b->legacy_io->write = pci_write_legacy_io;
        /* See pci_create_attr() for motivation */
-       b->legacy_io->llseek = pci_llseek_resource;
+       b->legacy_io->llseek = pci_llseek_resource_legacy;
        b->legacy_io->mmap = pci_mmap_legacy_io;
        b->legacy_io->f_mapping = iomem_get_mapping;
        pci_adjust_legacy_attr(b, pci_mmap_io);
@@ -1038,7 +1051,7 @@ void pci_create_legacy_files(struct pci_bus *b)
        b->legacy_mem->attr.mode = 0600;
        b->legacy_mem->mmap = pci_mmap_legacy_mem;
        /* See pci_create_attr() for motivation */
-       b->legacy_mem->llseek = pci_llseek_resource;
+       b->legacy_mem->llseek = pci_llseek_resource_legacy;
        b->legacy_mem->f_mapping = iomem_get_mapping;
        pci_adjust_legacy_attr(b, pci_mmap_mem);
        error = device_create_bin_file(&b->dev, b->legacy_mem);
-- 
2.54.0


Reply via email to