diff options
author | Yinghai Lu <yinghai@kernel.org> | 2012-04-02 21:31:53 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2012-04-30 15:52:17 -0400 |
commit | baa495d9de2af97310128bfc0e365a813b63d5bb (patch) | |
tree | 357ac52e1d76a3a71345e549ef207916f1e53326 /arch/x86/pci | |
parent | 610929e119b2166167f4f8fce85408472e77a16a (diff) |
x86/PCI: fix memleak with get_current_resources()
In pci_scan_acpi_root(), when pci_use_crs is set, get_current_resources()
is used to get pci_root_info, and it will allocate name and resource array.
Later if pci_create_root_bus() can not create bus (could be already
there...) it will only free bus res list, but the name and res array is not
freed.
Let get_current_resource() take info pointer instead of using local info.
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'arch/x86/pci')
-rw-r--r-- | arch/x86/pci/acpi.c | 49 |
1 files changed, 30 insertions, 19 deletions
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index ed2835e148b5..a99b7d75f5ca 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c | |||
@@ -315,49 +315,55 @@ static void add_resources(struct pci_root_info *info) | |||
315 | } | 315 | } |
316 | } | 316 | } |
317 | 317 | ||
318 | static void free_pci_root_info(struct pci_root_info *info) | ||
319 | { | ||
320 | kfree(info->name); | ||
321 | kfree(info->res); | ||
322 | memset(info, 0, sizeof(struct pci_root_info)); | ||
323 | } | ||
324 | |||
318 | static void | 325 | static void |
319 | get_current_resources(struct acpi_device *device, int busnum, | 326 | get_current_resources(struct pci_root_info *info, |
327 | struct acpi_device *device, int busnum, | ||
320 | int domain, struct list_head *resources) | 328 | int domain, struct list_head *resources) |
321 | { | 329 | { |
322 | struct pci_root_info info; | ||
323 | size_t size; | 330 | size_t size; |
324 | 331 | ||
325 | info.bridge = device; | 332 | info->bridge = device; |
326 | info.res_num = 0; | 333 | info->res_num = 0; |
327 | info.resources = resources; | 334 | info->resources = resources; |
328 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource, | 335 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource, |
329 | &info); | 336 | info); |
330 | if (!info.res_num) | 337 | if (!info->res_num) |
331 | return; | 338 | return; |
332 | 339 | ||
333 | size = sizeof(*info.res) * info.res_num; | 340 | size = sizeof(*info->res) * info->res_num; |
334 | info.res = kmalloc(size, GFP_KERNEL); | 341 | info->res = kmalloc(size, GFP_KERNEL); |
335 | if (!info.res) | 342 | if (!info->res) |
336 | return; | 343 | return; |
337 | 344 | ||
338 | info.name = kasprintf(GFP_KERNEL, "PCI Bus %04x:%02x", domain, busnum); | 345 | info->name = kasprintf(GFP_KERNEL, "PCI Bus %04x:%02x", domain, busnum); |
339 | if (!info.name) | 346 | if (!info->name) |
340 | goto name_alloc_fail; | 347 | goto name_alloc_fail; |
341 | 348 | ||
342 | info.res_num = 0; | 349 | info->res_num = 0; |
343 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource, | 350 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource, |
344 | &info); | 351 | info); |
345 | 352 | ||
346 | if (pci_use_crs) { | 353 | if (pci_use_crs) { |
347 | add_resources(&info); | 354 | add_resources(info); |
348 | 355 | ||
349 | return; | 356 | return; |
350 | } | 357 | } |
351 | 358 | ||
352 | kfree(info.name); | ||
353 | |||
354 | name_alloc_fail: | 359 | name_alloc_fail: |
355 | kfree(info.res); | 360 | free_pci_root_info(info); |
356 | } | 361 | } |
357 | 362 | ||
358 | struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) | 363 | struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) |
359 | { | 364 | { |
360 | struct acpi_device *device = root->device; | 365 | struct acpi_device *device = root->device; |
366 | struct pci_root_info info; | ||
361 | int domain = root->segment; | 367 | int domain = root->segment; |
362 | int busnum = root->secondary.start; | 368 | int busnum = root->secondary.start; |
363 | LIST_HEAD(resources); | 369 | LIST_HEAD(resources); |
@@ -402,6 +408,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) | |||
402 | 408 | ||
403 | sd->domain = domain; | 409 | sd->domain = domain; |
404 | sd->node = node; | 410 | sd->node = node; |
411 | memset(&info, 0, sizeof(struct pci_root_info)); | ||
405 | /* | 412 | /* |
406 | * Maybe the desired pci bus has been already scanned. In such case | 413 | * Maybe the desired pci bus has been already scanned. In such case |
407 | * it is unnecessary to scan the pci bus with the given domain,busnum. | 414 | * it is unnecessary to scan the pci bus with the given domain,busnum. |
@@ -415,7 +422,8 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) | |||
415 | memcpy(bus->sysdata, sd, sizeof(*sd)); | 422 | memcpy(bus->sysdata, sd, sizeof(*sd)); |
416 | kfree(sd); | 423 | kfree(sd); |
417 | } else { | 424 | } else { |
418 | get_current_resources(device, busnum, domain, &resources); | 425 | get_current_resources(&info, device, busnum, domain, |
426 | &resources); | ||
419 | 427 | ||
420 | /* | 428 | /* |
421 | * _CRS with no apertures is normal, so only fall back to | 429 | * _CRS with no apertures is normal, so only fall back to |
@@ -429,6 +437,9 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root) | |||
429 | bus->subordinate = pci_scan_child_bus(bus); | 437 | bus->subordinate = pci_scan_child_bus(bus); |
430 | else | 438 | else |
431 | pci_free_resource_list(&resources); | 439 | pci_free_resource_list(&resources); |
440 | |||
441 | if (!bus && pci_use_crs) | ||
442 | free_pci_root_info(&info); | ||
432 | } | 443 | } |
433 | 444 | ||
434 | /* After the PCI-E bus has been walked and all devices discovered, | 445 | /* After the PCI-E bus has been walked and all devices discovered, |