Message ID | 20180925162231.4354-3-logang@deltatee.com (mailing list archive) |
---|---|
State | New, archived |
Delegated to: | Bjorn Helgaas |
Headers | show |
Series | Copy Offload in NVMe Fabrics with P2P PCI Memory | expand |
On Tue, 2018-09-25 at 10:22 -0600, Logan Gunthorpe wrote: > @@ -83,9 +132,14 @@ static int pci_p2pdma_setup(struct pci_dev *pdev) > > pdev->p2pdma = p2p; > > + error = sysfs_create_group(&pdev->dev.kobj, &p2pmem_group); > + if (error) > + goto out_pool_destroy; > + > return 0; > > out_pool_destroy: > + pdev->p2pdma = NULL; > gen_pool_destroy(p2p->pool); > out: > devm_kfree(&pdev->dev, p2p); This doesn't look right to me. Shouldn't devm_remove_action() be called instead of devm_kfree() if sysfs_create_group() fails? Thanks, Bart.
On 2018-09-25 11:29 a.m., Bart Van Assche wrote: > On Tue, 2018-09-25 at 10:22 -0600, Logan Gunthorpe wrote: >> @@ -83,9 +132,14 @@ static int pci_p2pdma_setup(struct pci_dev *pdev) >> >> pdev->p2pdma = p2p; >> >> + error = sysfs_create_group(&pdev->dev.kobj, &p2pmem_group); >> + if (error) >> + goto out_pool_destroy; >> + >> return 0; >> >> out_pool_destroy: >> + pdev->p2pdma = NULL; >> gen_pool_destroy(p2p->pool); >> out: >> devm_kfree(&pdev->dev, p2p); > > This doesn't look right to me. Shouldn't devm_remove_action() be called instead > of devm_kfree() if sysfs_create_group() fails? That makes no sense to me. We are reversing a devm_kzalloc() not a custom action.... One could argue we should _also_ remove the pci_p2pdma_release() action, but seeing it has a NULL check on pdev->p2pdma it's pretty harmless to leave in. Logan
On Tue, 2018-09-25 at 12:15 -0600, Logan Gunthorpe wrote: > On 2018-09-25 11:29 a.m., Bart Van Assche wrote: > > On Tue, 2018-09-25 at 10:22 -0600, Logan Gunthorpe wrote: > > > @@ -83,9 +132,14 @@ static int pci_p2pdma_setup(struct pci_dev *pdev) > > > > > > pdev->p2pdma = p2p; > > > > > > + error = sysfs_create_group(&pdev->dev.kobj, &p2pmem_group); > > > + if (error) > > > + goto out_pool_destroy; > > > + > > > return 0; > > > > > > out_pool_destroy: > > > + pdev->p2pdma = NULL; > > > gen_pool_destroy(p2p->pool); > > > out: > > > devm_kfree(&pdev->dev, p2p); > > > > This doesn't look right to me. Shouldn't devm_remove_action() be called instead > > of devm_kfree() if sysfs_create_group() fails? > > That makes no sense to me. We are reversing a devm_kzalloc() not a > custom action.... In case what I wrote was not clear: both devm_kzalloc() and devm_add_action_or_reset() have to be reversed if sysfs_create_group() fails. devm_add_action_or_reset() calls devres_add(). The latter function adds an element to the dev->devres_head list. So I think that only calling devm_kfree() if sysfs_create_group() fails will lead to corruption of the dev->devres_head list. Bart.
On 2018-09-25 12:31 p.m., Bart Van Assche wrote: > On Tue, 2018-09-25 at 12:15 -0600, Logan Gunthorpe wrote: >> On 2018-09-25 11:29 a.m., Bart Van Assche wrote: >>> On Tue, 2018-09-25 at 10:22 -0600, Logan Gunthorpe wrote: >>>> @@ -83,9 +132,14 @@ static int pci_p2pdma_setup(struct pci_dev *pdev) >>>> >>>> pdev->p2pdma = p2p; >>>> >>>> + error = sysfs_create_group(&pdev->dev.kobj, &p2pmem_group); >>>> + if (error) >>>> + goto out_pool_destroy; >>>> + >>>> return 0; >>>> >>>> out_pool_destroy: >>>> + pdev->p2pdma = NULL; >>>> gen_pool_destroy(p2p->pool); >>>> out: >>>> devm_kfree(&pdev->dev, p2p); >>> >>> This doesn't look right to me. Shouldn't devm_remove_action() be called instead >>> of devm_kfree() if sysfs_create_group() fails? >> >> That makes no sense to me. We are reversing a devm_kzalloc() not a >> custom action.... > > In case what I wrote was not clear: both devm_kzalloc() and > devm_add_action_or_reset() have to be reversed if sysfs_create_group() fails. > devm_add_action_or_reset() calls devres_add(). The latter function adds an > element to the dev->devres_head list. So I think that only calling devm_kfree() > if sysfs_create_group() fails will lead to corruption of the dev->devres_head > list. I don't see how it would corrupt the list. devres_remove() uses list_del_init() which doesn't require that you only remove the tail from the list... The way I read the code, you can remove any devm action at any time. Logan
diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci index 44d4b2be92fd..8bfee557e50e 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci +++ b/Documentation/ABI/testing/sysfs-bus-pci @@ -323,3 +323,27 @@ Description: This is similar to /sys/bus/pci/drivers_autoprobe, but affects only the VFs associated with a specific PF. + +What: /sys/bus/pci/devices/.../p2pmem/size +Date: November 2017 +Contact: Logan Gunthorpe <logang@deltatee.com> +Description: + If the device has any Peer-to-Peer memory registered, this + file contains the total amount of memory that the device + provides (in decimal). + +What: /sys/bus/pci/devices/.../p2pmem/available +Date: November 2017 +Contact: Logan Gunthorpe <logang@deltatee.com> +Description: + If the device has any Peer-to-Peer memory registered, this + file contains the amount of memory that has not been + allocated (in decimal). + +What: /sys/bus/pci/devices/.../p2pmem/published +Date: November 2017 +Contact: Logan Gunthorpe <logang@deltatee.com> +Description: + If the device has any Peer-to-Peer memory registered, this + file contains a '1' if the memory has been published for + use outside the driver that owns the device. diff --git a/drivers/pci/p2pdma.c b/drivers/pci/p2pdma.c index d9616522c1fc..d61389945da2 100644 --- a/drivers/pci/p2pdma.c +++ b/drivers/pci/p2pdma.c @@ -24,6 +24,54 @@ struct pci_p2pdma { bool p2pmem_published; }; +static ssize_t size_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct pci_dev *pdev = to_pci_dev(dev); + size_t size = 0; + + if (pdev->p2pdma->pool) + size = gen_pool_size(pdev->p2pdma->pool); + + return snprintf(buf, PAGE_SIZE, "%zd\n", size); +} +static DEVICE_ATTR_RO(size); + +static ssize_t available_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct pci_dev *pdev = to_pci_dev(dev); + size_t avail = 0; + + if (pdev->p2pdma->pool) + avail = gen_pool_avail(pdev->p2pdma->pool); + + return snprintf(buf, PAGE_SIZE, "%zd\n", avail); +} +static DEVICE_ATTR_RO(available); + +static ssize_t published_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct pci_dev *pdev = to_pci_dev(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", + pdev->p2pdma->p2pmem_published); +} +static DEVICE_ATTR_RO(published); + +static struct attribute *p2pmem_attrs[] = { + &dev_attr_size.attr, + &dev_attr_available.attr, + &dev_attr_published.attr, + NULL, +}; + +static const struct attribute_group p2pmem_group = { + .attrs = p2pmem_attrs, + .name = "p2pmem", +}; + static void pci_p2pdma_percpu_release(struct percpu_ref *ref) { struct pci_p2pdma *p2p = @@ -53,6 +101,7 @@ static void pci_p2pdma_release(void *data) percpu_ref_exit(&pdev->p2pdma->devmap_ref); gen_pool_destroy(pdev->p2pdma->pool); + sysfs_remove_group(&pdev->dev.kobj, &p2pmem_group); pdev->p2pdma = NULL; } @@ -83,9 +132,14 @@ static int pci_p2pdma_setup(struct pci_dev *pdev) pdev->p2pdma = p2p; + error = sysfs_create_group(&pdev->dev.kobj, &p2pmem_group); + if (error) + goto out_pool_destroy; + return 0; out_pool_destroy: + pdev->p2pdma = NULL; gen_pool_destroy(p2p->pool); out: devm_kfree(&pdev->dev, p2p);