aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/osl.c
diff options
context:
space:
mode:
authorLin Ming <ming.m.lin@intel.com>2009-08-12 22:43:27 -0400
committerLen Brown <len.brown@intel.com>2009-08-27 13:10:35 -0400
commita5fe1a03f7720b8da8364a1737e1e5a357904e99 (patch)
tree2b84668217bc55d8a3bb98d053e92ff93b34dd36 /drivers/acpi/osl.c
parent422bef879e84104fee6dc68ded0e371dbeb5f88e (diff)
ACPICA: fix leak of acpi_os_validate_address
http://bugzilla.kernel.org/show_bug.cgi?id=13620 If the dynamic region is created and added to resource list over and over again, it has the potential to be a memory leak by growing the list every time. This patch fixes the memory leak, as below 1) add a new field "count" to struct acpi_res_list. When inserting, if the region(addr, len) is already in the resource list, we just increase "count", otherwise, the region is inserted with count=1. When deleting, the "count" is decreased, if it's decreased to 0, the region is deleted from the resource list. With "count", the region with same address and length can only be inserted to the resource list once, so prevent potential memory leak. 2) add a new function acpi_os_invalidate_address, which is called when region is deleted. Signed-off-by: Lin Ming <ming.m.lin@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/osl.c')
-rw-r--r--drivers/acpi/osl.c94
1 files changed, 91 insertions, 3 deletions
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 5691f165a952..c5b4f1ed9b71 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -88,6 +88,7 @@ struct acpi_res_list {
88 char name[5]; /* only can have a length of 4 chars, make use of this 88 char name[5]; /* only can have a length of 4 chars, make use of this
89 one instead of res->name, no need to kalloc then */ 89 one instead of res->name, no need to kalloc then */
90 struct list_head resource_list; 90 struct list_head resource_list;
91 int count;
91}; 92};
92 93
93static LIST_HEAD(resource_list_head); 94static LIST_HEAD(resource_list_head);
@@ -1358,6 +1359,89 @@ acpi_os_validate_interface (char *interface)
1358 return AE_SUPPORT; 1359 return AE_SUPPORT;
1359} 1360}
1360 1361
1362static inline int acpi_res_list_add(struct acpi_res_list *res)
1363{
1364 struct acpi_res_list *res_list_elem;
1365
1366 list_for_each_entry(res_list_elem, &resource_list_head,
1367 resource_list) {
1368
1369 if (res->resource_type == res_list_elem->resource_type &&
1370 res->start == res_list_elem->start &&
1371 res->end == res_list_elem->end) {
1372
1373 /*
1374 * The Region(addr,len) already exist in the list,
1375 * just increase the count
1376 */
1377
1378 res_list_elem->count++;
1379 return 0;
1380 }
1381 }
1382
1383 res->count = 1;
1384 list_add(&res->resource_list, &resource_list_head);
1385 return 1;
1386}
1387
1388static inline void acpi_res_list_del(struct acpi_res_list *res)
1389{
1390 struct acpi_res_list *res_list_elem;
1391
1392 list_for_each_entry(res_list_elem, &resource_list_head,
1393 resource_list) {
1394
1395 if (res->resource_type == res_list_elem->resource_type &&
1396 res->start == res_list_elem->start &&
1397 res->end == res_list_elem->end) {
1398
1399 /*
1400 * If the res count is decreased to 0,
1401 * remove and free it
1402 */
1403
1404 if (--res_list_elem->count == 0) {
1405 list_del(&res_list_elem->resource_list);
1406 kfree(res_list_elem);
1407 }
1408 return;
1409 }
1410 }
1411}
1412
1413acpi_status
1414acpi_os_invalidate_address(
1415 u8 space_id,
1416 acpi_physical_address address,
1417 acpi_size length)
1418{
1419 struct acpi_res_list res;
1420
1421 switch (space_id) {
1422 case ACPI_ADR_SPACE_SYSTEM_IO:
1423 case ACPI_ADR_SPACE_SYSTEM_MEMORY:
1424 /* Only interference checks against SystemIO and SytemMemory
1425 are needed */
1426 res.start = address;
1427 res.end = address + length - 1;
1428 res.resource_type = space_id;
1429 spin_lock(&acpi_res_lock);
1430 acpi_res_list_del(&res);
1431 spin_unlock(&acpi_res_lock);
1432 break;
1433 case ACPI_ADR_SPACE_PCI_CONFIG:
1434 case ACPI_ADR_SPACE_EC:
1435 case ACPI_ADR_SPACE_SMBUS:
1436 case ACPI_ADR_SPACE_CMOS:
1437 case ACPI_ADR_SPACE_PCI_BAR_TARGET:
1438 case ACPI_ADR_SPACE_DATA_TABLE:
1439 case ACPI_ADR_SPACE_FIXED_HARDWARE:
1440 break;
1441 }
1442 return AE_OK;
1443}
1444
1361/****************************************************************************** 1445/******************************************************************************
1362 * 1446 *
1363 * FUNCTION: acpi_os_validate_address 1447 * FUNCTION: acpi_os_validate_address
@@ -1382,6 +1466,7 @@ acpi_os_validate_address (
1382 char *name) 1466 char *name)
1383{ 1467{
1384 struct acpi_res_list *res; 1468 struct acpi_res_list *res;
1469 int added;
1385 if (acpi_enforce_resources == ENFORCE_RESOURCES_NO) 1470 if (acpi_enforce_resources == ENFORCE_RESOURCES_NO)
1386 return AE_OK; 1471 return AE_OK;
1387 1472
@@ -1399,14 +1484,17 @@ acpi_os_validate_address (
1399 res->end = address + length - 1; 1484 res->end = address + length - 1;
1400 res->resource_type = space_id; 1485 res->resource_type = space_id;
1401 spin_lock(&acpi_res_lock); 1486 spin_lock(&acpi_res_lock);
1402 list_add(&res->resource_list, &resource_list_head); 1487 added = acpi_res_list_add(res);
1403 spin_unlock(&acpi_res_lock); 1488 spin_unlock(&acpi_res_lock);
1404 pr_debug("Added %s resource: start: 0x%llx, end: 0x%llx, " 1489 pr_debug("%s %s resource: start: 0x%llx, end: 0x%llx, "
1405 "name: %s\n", (space_id == ACPI_ADR_SPACE_SYSTEM_IO) 1490 "name: %s\n", added ? "Added" : "Already exist",
1491 (space_id == ACPI_ADR_SPACE_SYSTEM_IO)
1406 ? "SystemIO" : "System Memory", 1492 ? "SystemIO" : "System Memory",
1407 (unsigned long long)res->start, 1493 (unsigned long long)res->start,
1408 (unsigned long long)res->end, 1494 (unsigned long long)res->end,
1409 res->name); 1495 res->name);
1496 if (!added)
1497 kfree(res);
1410 break; 1498 break;
1411 case ACPI_ADR_SPACE_PCI_CONFIG: 1499 case ACPI_ADR_SPACE_PCI_CONFIG:
1412 case ACPI_ADR_SPACE_EC: 1500 case ACPI_ADR_SPACE_EC: