Re: [PATCH v3 6/8] PCI: Rework of_pci_get_host_bridge_resources() to devm_of_pci_get_host_bridge_resources()

From: Vladimir Zapolskiy
Date: Tue May 15 2018 - 03:54:24 EST


Hi Jan,

On 05/15/2018 08:58 AM, Jan Kiszka wrote:
> From: Jan Kiszka <jan.kiszka@xxxxxxxxxxx>
>
> of_pci_get_host_bridge_resources() allocates the resource structures it
> fills dynamically, but none of its callers care to release them so far.
> Rather than requiring everyone to do this explicitly, convert the
> existing function to a managed version.
>
> CC: Jingoo Han <jingoohan1@xxxxxxxxx>
> CC: Joao Pinto <Joao.Pinto@xxxxxxxxxxxx>
> CC: Lorenzo Pieralisi <lorenzo.pieralisi@xxxxxxx>
> Signed-off-by: Jan Kiszka <jan.kiszka@xxxxxxxxxxx>

[snip]

> diff --git a/drivers/pci/of.c b/drivers/pci/of.c
> index 4f21514cb4e4..00f42389aa56 100644
> --- a/drivers/pci/of.c
> +++ b/drivers/pci/of.c
> @@ -244,7 +244,8 @@ EXPORT_SYMBOL_GPL(of_pci_check_probe_only);
>
> #if defined(CONFIG_OF_ADDRESS)
> /**
> - * of_pci_get_host_bridge_resources - Parse PCI host bridge resources from DT
> + * devm_of_pci_get_host_bridge_resources() - Resource-managed parsing of PCI
> + * host bridge resources from DT
> * @dev: host bridge device
> * @busno: bus number associated with the bridge root bus
> * @bus_max: maximum number of buses for this bridge
> @@ -253,8 +254,6 @@ EXPORT_SYMBOL_GPL(of_pci_check_probe_only);
> * address for the start of the I/O range. Can be NULL if the caller doesn't
> * expect I/O ranges to be present in the device tree.
> *
> - * It is the caller's job to free the @resources list.
> - *
> * This function will parse the "ranges" property of a PCI host bridge device
> * node and setup the resource mapping based on its content. It is expected
> * that the property conforms with the Power ePAPR document.
> @@ -262,12 +261,11 @@ EXPORT_SYMBOL_GPL(of_pci_check_probe_only);
> * It returns zero if the range parsing has been successful or a standard error
> * value if it failed.
> */
> -int of_pci_get_host_bridge_resources(struct device *dev,
> +int devm_of_pci_get_host_bridge_resources(struct device *dev,
> unsigned char busno, unsigned char bus_max,
> struct list_head *resources, resource_size_t *io_base)
> {
> struct device_node *dev_node = dev->of_node;
> - struct resource_entry *window;
> struct resource *res;
> struct resource *bus_range;
> struct of_pci_range range;
> @@ -278,7 +276,7 @@ int of_pci_get_host_bridge_resources(struct device *dev,
> if (io_base)
> *io_base = (resource_size_t)OF_BAD_ADDR;
>
> - bus_range = kzalloc(sizeof(*bus_range), GFP_KERNEL);
> + bus_range = devm_kzalloc(dev, sizeof(*bus_range), GFP_KERNEL);
> if (!bus_range)
> return -ENOMEM;
>
> @@ -300,7 +298,7 @@ int of_pci_get_host_bridge_resources(struct device *dev,
> /* Check for ranges property */
> err = of_pci_range_parser_init(&parser, dev_node);
> if (err)
> - goto parse_failed;
> + return err;

In my opinion allocated by pci_add_resource() and pci_add_resource_offset()
resource entries are leaked on error paths, and pci_free_resource_list() should
be called.

>
> dev_dbg(dev, "Parsing ranges property...\n");
> for_each_of_pci_range(&parser, &range) {
> @@ -322,15 +320,13 @@ int of_pci_get_host_bridge_resources(struct device *dev,
> if (range.cpu_addr == OF_BAD_ADDR || range.size == 0)
> continue;
>
> - res = kzalloc(sizeof(struct resource), GFP_KERNEL);
> - if (!res) {
> - err = -ENOMEM;
> - goto parse_failed;
> - }
> + res = devm_kzalloc(dev, sizeof(struct resource), GFP_KERNEL);
> + if (!res)
> + return -ENOMEM;

Same as above.

>
> err = of_pci_range_to_resource(&range, dev_node, res);
> if (err) {
> - kfree(res);
> + devm_kfree(dev, res);
> continue;
> }
>
> @@ -339,8 +335,7 @@ int of_pci_get_host_bridge_resources(struct device *dev,
> dev_err(dev,
> "I/O range found for %pOF. Please provide an io_base pointer to save CPU base address\n",
> dev_node);
> - err = -EINVAL;
> - goto conversion_failed;
> + return -EINVAL;

Same as above.

> }
> if (*io_base != (resource_size_t)OF_BAD_ADDR)
> dev_warn(dev,
> @@ -353,16 +348,8 @@ int of_pci_get_host_bridge_resources(struct device *dev,
> }
>
> return 0;
> -
> -conversion_failed:
> - kfree(res);
> -parse_failed:
> - resource_list_for_each_entry(window, resources)
> - kfree(window->res);
> - pci_free_resource_list(resources);
> - return err;
> }
> -EXPORT_SYMBOL_GPL(of_pci_get_host_bridge_resources);
> +EXPORT_SYMBOL_GPL(devm_of_pci_get_host_bridge_resources);
> #endif /* CONFIG_OF_ADDRESS */
>
> /**
> @@ -606,7 +593,7 @@ int pci_parse_request_of_pci_ranges(struct device *dev,
> struct resource_entry *win, *tmp;
>
> INIT_LIST_HEAD(resources);
> - err = of_pci_get_host_bridge_resources(dev, 0, 0xff, resources,
> + err = devm_of_pci_get_host_bridge_resources(dev, 0, 0xff, resources,
> &iobase);
> if (err)
> return err;

--
With best wishes,
Vladimir