[PATCH v8 45/45] PCI/hotplug: PowerPC PowerNV PCI hotplug driver
Alistair Popple
alistair at popple.id.au
Fri Apr 15 10:47:52 AEST 2016
Hi Gavin,
I was reading through this to understand how it all works and noticed a couple
of things, comments below.
- Alistair
On Wed, 17 Feb 2016 14:44:28 Gavin Shan wrote:
<snip>
> +
> +static void pnv_php_handle_poweron(struct pnv_php_slot *php_slot)
> +{
> + void *fdt, *fdt1, *dt;
> + int confirm = PNV_PHP_POWER_CONFIRMED_SUCCESS;
> + int ret;
> +
> + /* We don't know the FDT blob size. We try to get it through
> + * maximal memory chunk and then copy it to another chunk that
> + * fits the real size.
> + */
> + fdt1 = kzalloc(0x10000, GFP_KERNEL);
> + if (!fdt1)
> + goto error;
> +
> + ret = pnv_pci_get_device_tree(php_slot->dn->phandle, fdt1, 0x10000);
> + if (ret)
> + goto free_fdt1;
> +
> + fdt = kzalloc(fdt_totalsize(fdt1), GFP_KERNEL);
> + if (!fdt)
> + goto free_fdt1;
> +
> + /* Unflatten device tree blob */
> + memcpy(fdt, fdt1, fdt_totalsize(fdt1));
> + dt = of_fdt_unflatten_tree(fdt, php_slot->dn, NULL);
> + if (!dt) {
> + dev_warn(&php_slot->pdev->dev, "Cannot unflatten FDT\n");
> + goto free_fdt;
> + }
> +
> + /* Initialize and apply the changeset */
> + of_changeset_init(&php_slot->ocs);
> + ret = pnv_php_populate_changeset(&php_slot->ocs, php_slot->dn);
> + if (ret) {
> + dev_warn(&php_slot->pdev->dev, "Error %d populating changeset\n",
> + ret);
> + goto free_dt;
> + }
> +
> + php_slot->dn->child = NULL;
> + ret = of_changeset_apply(&php_slot->ocs);
> + if (ret) {
> + dev_warn(&php_slot->pdev->dev, "Error %d applying changeset\n",
> + ret);
> + goto destroy_changeset;
> + }
> +
> + /* Add device node firmware data */
> + pnv_php_add_pdns(php_slot);
> + php_slot->fdt = fdt;
> + php_slot->dt = dt;
> + goto out;
Doesn't this leak memory from fdt1? I can't see where it gets freed in this
case.
> +destroy_changeset:
> + of_changeset_destroy(&php_slot->ocs);
> +free_dt:
> + kfree(dt);
> + php_slot->dn->child = NULL;
> +free_fdt:
> + kfree(fdt);
> +free_fdt1:
> + kfree(fdt1);
> +error:
> + confirm = PNV_PHP_POWER_CONFIRMED_FAIL;
> +out:
> + /* Confirm status change */
> + php_slot->power_state_confirmed = confirm;
> + wake_up_interruptible(&php_slot->queue);
> +}
> +
<snip>
> +
> +static void __exit pnv_php_exit(void)
> +{
> + struct device_node *dn;
> +
> + for_each_compatible_node(dn, NULL, "ibm,ioda-phb")
> + pnv_php_unregister(dn);
> + for_each_compatible_node(dn, NULL, "ibm,ioda2-phb")
> + pnv_php_unregister(dn);
> +
> + pnv_pci_hotplug_notifier_unregister(&php_msg_nb);
Do you flush the workqueues anywhere? Usually you would stop work being queued
and call something like flush_workqueue() to ensure no work is still
running/queued before unloading the module.
- Alistair
> +}
> +
> +module_init(pnv_php_init);
> +module_exit(pnv_php_exit);
> +
> +MODULE_VERSION(DRIVER_VERSION);
> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR(DRIVER_AUTHOR);
> +MODULE_DESCRIPTION(DRIVER_DESC);
>
More information about the Linuxppc-dev
mailing list