diff mbox series

[v7,02/13] PCI/P2PDMA: Add sysfs group to display p2pmem stats

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

Commit Message

Logan Gunthorpe Sept. 25, 2018, 4:22 p.m. UTC
Add a sysfs group to display statistics about P2P memory that is
registered in each PCI device.

Attributes in the group display the total amount of P2P memory, the
amount available and whether it is published or not.

Signed-off-by: Logan Gunthorpe <logang@deltatee.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
---
 Documentation/ABI/testing/sysfs-bus-pci | 24 +++++++++++
 drivers/pci/p2pdma.c                    | 54 +++++++++++++++++++++++++
 2 files changed, 78 insertions(+)

Comments

Bart Van Assche Sept. 25, 2018, 5:29 p.m. UTC | #1
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.
Logan Gunthorpe Sept. 25, 2018, 6:15 p.m. UTC | #2
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
Bart Van Assche Sept. 25, 2018, 6:31 p.m. UTC | #3
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.
Logan Gunthorpe Sept. 25, 2018, 6:51 p.m. UTC | #4
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 mbox series

Patch

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);