diff options
author | Jiang Liu <jiang.liu@huawei.com> | 2013-06-06 03:34:50 -0400 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2013-06-18 12:46:22 -0400 |
commit | c9e391cf1b3c1c46bf79c75b3bc5677909fcd625 (patch) | |
tree | 5193de45c9010e633e571ca655e7d40176c97e4d /arch/ia64/pci/pci.c | |
parent | 429ac0995e74b24d83ca058e802faed9a562651b (diff) |
PCI/IA64: fix memleak for create pci root bus fail
If pci_create_root_bus() return fail, we should release
pci root info, pci controller etc.
Signed-off-by: Jiang Liu <jiang.liu@huawei.com>
Signed-off-by: Yijing Wang <wangyijing@huawei.com>
Cc: Fenghua Yu <fenghua.yu@intel.com>
Cc: Yinghai Lu <yinghai@kernel.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: linux-ia64@vger.kernel.org
Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'arch/ia64/pci/pci.c')
-rw-r--r-- | arch/ia64/pci/pci.c | 74 |
1 files changed, 60 insertions, 14 deletions
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 6da469a38a49..99a9f672d156 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c | |||
@@ -137,6 +137,7 @@ struct pci_root_info { | |||
137 | struct resource *res; | 137 | struct resource *res; |
138 | resource_size_t *res_offset; | 138 | resource_size_t *res_offset; |
139 | unsigned int res_num; | 139 | unsigned int res_num; |
140 | struct list_head io_resources; | ||
140 | char *name; | 141 | char *name; |
141 | }; | 142 | }; |
142 | 143 | ||
@@ -171,25 +172,21 @@ new_space (u64 phys_base, int sparse) | |||
171 | static u64 add_io_space(struct pci_root_info *info, | 172 | static u64 add_io_space(struct pci_root_info *info, |
172 | struct acpi_resource_address64 *addr) | 173 | struct acpi_resource_address64 *addr) |
173 | { | 174 | { |
175 | struct iospace_resource *iospace; | ||
174 | struct resource *resource; | 176 | struct resource *resource; |
175 | char *name; | 177 | char *name; |
176 | unsigned long base, min, max, base_port; | 178 | unsigned long base, min, max, base_port; |
177 | unsigned int sparse = 0, space_nr, len; | 179 | unsigned int sparse = 0, space_nr, len; |
178 | 180 | ||
179 | resource = kzalloc(sizeof(*resource), GFP_KERNEL); | 181 | len = strlen(info->name) + 32; |
180 | if (!resource) { | 182 | iospace = kzalloc(sizeof(*iospace) + len, GFP_KERNEL); |
183 | if (!iospace) { | ||
181 | printk(KERN_ERR "PCI: No memory for %s I/O port space\n", | 184 | printk(KERN_ERR "PCI: No memory for %s I/O port space\n", |
182 | info->name); | 185 | info->name); |
183 | goto out; | 186 | goto out; |
184 | } | 187 | } |
185 | 188 | ||
186 | len = strlen(info->name) + 32; | 189 | name = (char *)(iospace + 1); |
187 | name = kzalloc(len, GFP_KERNEL); | ||
188 | if (!name) { | ||
189 | printk(KERN_ERR "PCI: No memory for %s I/O port space name\n", | ||
190 | info->name); | ||
191 | goto free_resource; | ||
192 | } | ||
193 | 190 | ||
194 | min = addr->minimum; | 191 | min = addr->minimum; |
195 | max = min + addr->address_length - 1; | 192 | max = min + addr->address_length - 1; |
@@ -198,7 +195,7 @@ static u64 add_io_space(struct pci_root_info *info, | |||
198 | 195 | ||
199 | space_nr = new_space(addr->translation_offset, sparse); | 196 | space_nr = new_space(addr->translation_offset, sparse); |
200 | if (space_nr == ~0) | 197 | if (space_nr == ~0) |
201 | goto free_name; | 198 | goto free_resource; |
202 | 199 | ||
203 | base = __pa(io_space[space_nr].mmio_base); | 200 | base = __pa(io_space[space_nr].mmio_base); |
204 | base_port = IO_SPACE_BASE(space_nr); | 201 | base_port = IO_SPACE_BASE(space_nr); |
@@ -213,18 +210,23 @@ static u64 add_io_space(struct pci_root_info *info, | |||
213 | if (space_nr == 0) | 210 | if (space_nr == 0) |
214 | sparse = 1; | 211 | sparse = 1; |
215 | 212 | ||
213 | resource = &iospace->res; | ||
216 | resource->name = name; | 214 | resource->name = name; |
217 | resource->flags = IORESOURCE_MEM; | 215 | resource->flags = IORESOURCE_MEM; |
218 | resource->start = base + (sparse ? IO_SPACE_SPARSE_ENCODING(min) : min); | 216 | resource->start = base + (sparse ? IO_SPACE_SPARSE_ENCODING(min) : min); |
219 | resource->end = base + (sparse ? IO_SPACE_SPARSE_ENCODING(max) : max); | 217 | resource->end = base + (sparse ? IO_SPACE_SPARSE_ENCODING(max) : max); |
220 | insert_resource(&iomem_resource, resource); | 218 | if (insert_resource(&iomem_resource, resource)) { |
219 | dev_err(&info->bridge->dev, | ||
220 | "can't allocate host bridge io space resource %pR\n", | ||
221 | resource); | ||
222 | goto free_resource; | ||
223 | } | ||
221 | 224 | ||
225 | list_add_tail(&iospace->list, &info->io_resources); | ||
222 | return base_port; | 226 | return base_port; |
223 | 227 | ||
224 | free_name: | ||
225 | kfree(name); | ||
226 | free_resource: | 228 | free_resource: |
227 | kfree(resource); | 229 | kfree(iospace); |
228 | out: | 230 | out: |
229 | return ~0; | 231 | return ~0; |
230 | } | 232 | } |
@@ -325,6 +327,48 @@ static acpi_status add_window(struct acpi_resource *res, void *data) | |||
325 | return AE_OK; | 327 | return AE_OK; |
326 | } | 328 | } |
327 | 329 | ||
330 | static void free_pci_root_info_res(struct pci_root_info *info) | ||
331 | { | ||
332 | struct iospace_resource *iospace, *tmp; | ||
333 | |||
334 | list_for_each_entry_safe(iospace, tmp, &info->io_resources, list) | ||
335 | kfree(iospace); | ||
336 | |||
337 | kfree(info->name); | ||
338 | kfree(info->res); | ||
339 | info->res = NULL; | ||
340 | kfree(info->res_offset); | ||
341 | info->res_offset = NULL; | ||
342 | info->res_num = 0; | ||
343 | kfree(info->controller); | ||
344 | info->controller = NULL; | ||
345 | } | ||
346 | |||
347 | static void __release_pci_root_info(struct pci_root_info *info) | ||
348 | { | ||
349 | int i; | ||
350 | struct resource *res; | ||
351 | struct iospace_resource *iospace; | ||
352 | |||
353 | list_for_each_entry(iospace, &info->io_resources, list) | ||
354 | release_resource(&iospace->res); | ||
355 | |||
356 | for (i = 0; i < info->res_num; i++) { | ||
357 | res = &info->res[i]; | ||
358 | |||
359 | if (!res->parent) | ||
360 | continue; | ||
361 | |||
362 | if (!(res->flags & (IORESOURCE_MEM | IORESOURCE_IO))) | ||
363 | continue; | ||
364 | |||
365 | release_resource(res); | ||
366 | } | ||
367 | |||
368 | free_pci_root_info_res(info); | ||
369 | kfree(info); | ||
370 | } | ||
371 | |||
328 | struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) | 372 | struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) |
329 | { | 373 | { |
330 | struct acpi_device *device = root->device; | 374 | struct acpi_device *device = root->device; |
@@ -357,6 +401,7 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) | |||
357 | goto out2; | 401 | goto out2; |
358 | } | 402 | } |
359 | 403 | ||
404 | INIT_LIST_HEAD(&info->io_resources); | ||
360 | INIT_LIST_HEAD(&info->resources); | 405 | INIT_LIST_HEAD(&info->resources); |
361 | /* insert busn resource at first */ | 406 | /* insert busn resource at first */ |
362 | pci_add_resource(&info->resources, &root->secondary); | 407 | pci_add_resource(&info->resources, &root->secondary); |
@@ -397,6 +442,7 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) | |||
397 | &info->resources); | 442 | &info->resources); |
398 | if (!pbus) { | 443 | if (!pbus) { |
399 | pci_free_resource_list(&info->resources); | 444 | pci_free_resource_list(&info->resources); |
445 | __release_pci_root_info(info); | ||
400 | return NULL; | 446 | return NULL; |
401 | } | 447 | } |
402 | 448 | ||