KASAN reports as fllowing:
[ 478.962411] Call trace: [ 478.962450] device_remove_properties+0x6c/0xb4 [ 478.962457] device_del+0x2d8/0x660 [ 478.962465] pci_remove_bus_device+0xc4/0x1a0 [ 478.962470] pci_stop_and_remove_bus_device+0x94/0xb0 [ 478.962477] pci_iov_remove_virtfn+0x160/0x210 [ 478.962481] sriov_disable+0x70/0x1ac [ 478.962486] pci_disable_sriov+0x34/0x44
[ 478.964837] Allocated by task 10258: [ 478.969197] kmem_cache_alloc_trace+0xe0/0x570 [ 478.969204] swnode_register+0x54/0x310 [ 478.969208] fwnode_create_software_node+0xf8/0x130 [ 478.969215] device_add_properties+0x28/0x50 [ 478.969221] quirk_huawei_pcie_sva+0x12c/0x14c [ 478.969225] pci_do_fixups+0x120/0x1b0 [ 478.969229] pci_fixup_device+0x4c/0x140 [ 478.969233] pci_bus_add_device+0x2c/0xd4 [ 478.969237] pci_iov_add_virtfn+0x470/0x49c [ 478.969241] sriov_enable+0x368/0x690 [ 478.969246] pci_enable_sriov+0x3c/0x54
[ 478.971557] Freed by task 10258: [ 478.975570] kfree+0xe4/0x6b0 [ 478.975574] software_node_release+0xf4/0x16c [ 478.975578] kobject_cleanup+0x158/0x1a8 [ 478.975582] kobject_put.part.0+0x9c/0xf4 [ 478.975587] kobject_put+0x18/0x24 [ 478.975591] software_node_notify+0xe8/0x1a0 [ 478.975595] device_platform_notify+0x54/0xc0 [ 478.975599] device_del+0x2c8/0x660 [ 478.975603] pci_remove_bus_device+0xc4/0x1a0 [ 478.975607] pci_stop_and_remove_bus_device+0x94/0xb0 [ 478.975612] pci_iov_remove_virtfn+0x160/0x210
device_add() should be called after device_add_properties(), address this issue by replacing device_add_properties() with device_create_managed_software_node().
Heikki Krogerus (2): [Backport] software node: Provide replacement for device_add_properties() [Backport] PCI: Convert to device_create_managed_software_node()
drivers/base/swnode.c | 43 ++++++++++++++++++++++++++++++++++++++++ drivers/pci/quirks.c | 2 +- include/linux/property.h | 4 ++++ 3 files changed, 48 insertions(+), 1 deletion(-)
From: Heikki Krogerus heikki.krogerus@linux.intel.com
mainline inclusion from mainline-v5.12-rc1-dontuse commit 151f6ff78cdf1d6de76e90556cfc43f1e48abe18 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I7WMEY
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
--------------------------------
At the moment the function device_del() is calling device_remove_properties() unconditionally. That will result into the reference count of the software node attached to the device being decremented, and in most cases it will hit 0 at that point. So in practice device_del() will unregister the software node attached to the device, even if that was not the intention of the caller. Right now software nodes can not be reused or shared because of that.
So device_del() can not unregister the software nodes unconditionally like that. Unfortunately some of the users of device_add_properties() are now relying on this behaviour. Because of that, and also in general, we do need a function that can offer similar behaviour where the lifetime of the software node is bound to the lifetime of the device. But it just has to be a separate function so the behaviour is optional. We can not remove the device_remove_properties() call from device_del() before we have that new function, and before we have replaced device_add_properties() calls with it in all the places that require that behaviour.
This adds function device_create_managed_software_node() that can be used for exactly that purpose. Software nodes created with it are declared "managed", and separate handling for those nodes is added to the software node code. The reference count of the "managed" nodes is decremented when the device they are attached to is removed. This will not affect the other nodes that are not declared "managed".
The function device_create_managed_software_node() has also one additional feature that device_add_properties() does not have. It allows the software nodes created with it to be part of a node hierarchy by taking also an optional parent node as parameter.
Reviewed-by: Rafael J. Wysocki rafael.j.wysocki@intel.com Signed-off-by: Heikki Krogerus heikki.krogerus@linux.intel.com Link: https://lore.kernel.org/r/20210204141711.53775-2-heikki.krogerus@linux.intel... Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
Conflicts: drivers/base/swnode.c include/linux/property.h
Signed-off-by: Yu Liao liaoyu15@huawei.com --- drivers/base/swnode.c | 43 ++++++++++++++++++++++++++++++++++++++++ include/linux/property.h | 4 ++++ 2 files changed, 47 insertions(+)
diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c index d2fb3eb5816c..202e3b70ab99 100644 --- a/drivers/base/swnode.c +++ b/drivers/base/swnode.c @@ -24,6 +24,7 @@ struct swnode { struct swnode *parent;
unsigned int allocated:1; + unsigned int managed:1; };
static DEFINE_IDA(swnode_root_ids); @@ -850,6 +851,43 @@ void fwnode_remove_software_node(struct fwnode_handle *fwnode) } EXPORT_SYMBOL_GPL(fwnode_remove_software_node);
+/** + * device_create_managed_software_node - Create a software node for a device + * @dev: The device the software node is assigned to. + * @properties: Device properties for the software node. + * @parent: Parent of the software node. + * + * Creates a software node as a managed resource for @dev, which means the + * lifetime of the newly created software node is tied to the lifetime of @dev. + * Software nodes created with this function should not be reused or shared + * because of that. The function takes a deep copy of @properties for the + * software node. + * + * Since the new software node is assigned directly to @dev, and since it should + * not be shared, it is not returned to the caller. The function returns 0 on + * success, and errno in case of an error. + */ +int device_create_managed_software_node(struct device *dev, + const struct property_entry *properties, + const struct software_node *parent) +{ + struct fwnode_handle *p = software_node_fwnode(parent); + struct fwnode_handle *fwnode; + + if (parent && !p) + return -EINVAL; + + fwnode = fwnode_create_software_node(properties, p); + if (IS_ERR(fwnode)) + return PTR_ERR(fwnode); + + to_swnode(fwnode)->managed = true; + set_secondary_fwnode(dev, fwnode); + + return 0; +} +EXPORT_SYMBOL_GPL(device_create_managed_software_node); + int software_node_notify(struct device *dev, unsigned long action) { struct fwnode_handle *fwnode = dev_fwnode(dev); @@ -885,6 +923,11 @@ int software_node_notify(struct device *dev, unsigned long action) sysfs_remove_link(&swnode->kobj, dev_name(dev)); sysfs_remove_link(&dev->kobj, "software_node"); kobject_put(&swnode->kobj); + + if (swnode->managed) { + set_secondary_fwnode(dev, NULL); + kobject_put(&swnode->kobj); + } break; default: break; diff --git a/include/linux/property.h b/include/linux/property.h index 2d4542629d80..6919d81caeb9 100644 --- a/include/linux/property.h +++ b/include/linux/property.h @@ -485,4 +485,8 @@ fwnode_create_software_node(const struct property_entry *properties, const struct fwnode_handle *parent); void fwnode_remove_software_node(struct fwnode_handle *fwnode);
+int device_create_managed_software_node(struct device *dev, + const struct property_entry *properties, + const struct software_node *parent); + #endif /* _LINUX_PROPERTY_H_ */
From: Heikki Krogerus heikki.krogerus@linux.intel.com
mainline inclusion from mainline-v5.17-rc1 commit 0c9e032a45e777b707bd8ae282242a2b9be3ac91 category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I7WMEY
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
--------------------------------
In quirk_huawei_pcie_sva(), device_add_properties() is used to inject additional device properties, but there is no device_remove_properties() call anywhere to remove those properties. The assumption is most likely that the device is never removed, and the properties therefore do not also never need to be removed.
Even though it is unlikely that the device is ever removed in this case, it is safer to make sure that the properties are also removed if the device ever does get unregistered.
To achieve this, instead of adding a separate quirk for the case of device removal where device_remove_properties() is called, using device_create_managed_software_node() instead of device_add_properties(). Both functions create a software node (a type of fwnode) that holds the device properties, which is then assigned to the device very much the same way.
The difference between the two functions is, that device_create_managed_software_node() guarantees that the software node (together with the properties) is removed when the device is removed. The function device_add_property() does not guarantee that, so the properties added with it should always be removed with device_remove_properties().
Reviewed-by: Andy Shevchenko andy.shevchenko@gmail.com Acked-by: Zhangfei Gao zhangfei.gao@linaro.org Acked-by: Bjorn Helgaas bhelgaas@google.com Signed-off-by: Heikki Krogerus heikki.krogerus@linux.intel.com Signed-off-by: Rafael J. Wysocki rafael.j.wysocki@intel.com Signed-off-by: Yu Liao liaoyu15@huawei.com --- drivers/pci/quirks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 4fc517689699..8783caa316a6 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1855,7 +1855,7 @@ static void quirk_huawei_pcie_sva(struct pci_dev *pdev) * can set it directly. */ if (!pdev->dev.of_node && - device_add_properties(&pdev->dev, properties)) + device_create_managed_software_node(&pdev->dev, properties, NULL)) pci_warn(pdev, "could not add stall property"); } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_HUAWEI, 0xa250, quirk_huawei_pcie_sva);
反馈: 您发送到kernel@openeuler.org的补丁/补丁集,已成功转换为PR! PR链接地址: https://gitee.com/openeuler/kernel/pulls/1907 邮件列表地址:https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/3...
FeedBack: The patch(es) which you have sent to kernel@openeuler.org mailing list has been converted to a pull request successfully! Pull request link: https://gitee.com/openeuler/kernel/pulls/1907 Mailing list address: https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/3...