agp/uninorth: fix a memleak in create_gatt_table
authorDenis Kirjanov <kda@linux-powerpc.org>
Fri, 12 Jun 2015 06:57:11 +0000 (09:57 +0300)
committerMichael Ellerman <mpe@ellerman.id.au>
Fri, 2 Oct 2015 12:57:59 +0000 (22:57 +1000)
Fix the memory leak in create_gatt_table:
we've lost a kfree on the exit path for the pages array allocated
in uninorth_create_gatt_table

Signed-off-by: Denis Kirjanov <kda@linux-powerpc.org>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
drivers/char/agp/uninorth-agp.c

index a56ee9bedd112ddeea5551ba922a7d767ab7cd3b..05755441250c1de8495725ea80253957b71abd07 100644 (file)
@@ -361,6 +361,10 @@ static int agp_uninorth_resume(struct pci_dev *pdev)
 }
 #endif /* CONFIG_PM */
 
+static struct {
+       struct page **pages_arr;
+} uninorth_priv;
+
 static int uninorth_create_gatt_table(struct agp_bridge_data *bridge)
 {
        char *table;
@@ -371,7 +375,6 @@ static int uninorth_create_gatt_table(struct agp_bridge_data *bridge)
        int i;
        void *temp;
        struct page *page;
-       struct page **pages;
 
        /* We can't handle 2 level gatt's */
        if (bridge->driver->size_type == LVL2_APER_SIZE)
@@ -400,8 +403,8 @@ static int uninorth_create_gatt_table(struct agp_bridge_data *bridge)
        if (table == NULL)
                return -ENOMEM;
 
-       pages = kmalloc((1 << page_order) * sizeof(struct page*), GFP_KERNEL);
-       if (pages == NULL)
+       uninorth_priv.pages_arr = kmalloc((1 << page_order) * sizeof(struct page*), GFP_KERNEL);
+       if (uninorth_priv.pages_arr == NULL)
                goto enomem;
 
        table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
@@ -409,14 +412,14 @@ static int uninorth_create_gatt_table(struct agp_bridge_data *bridge)
        for (page = virt_to_page(table), i = 0; page <= virt_to_page(table_end);
             page++, i++) {
                SetPageReserved(page);
-               pages[i] = page;
+               uninorth_priv.pages_arr[i] = page;
        }
 
        bridge->gatt_table_real = (u32 *) table;
        /* Need to clear out any dirty data still sitting in caches */
        flush_dcache_range((unsigned long)table,
                           (unsigned long)table_end + 1);
-       bridge->gatt_table = vmap(pages, (1 << page_order), 0, PAGE_KERNEL_NCG);
+       bridge->gatt_table = vmap(uninorth_priv.pages_arr, (1 << page_order), 0, PAGE_KERNEL_NCG);
 
        if (bridge->gatt_table == NULL)
                goto enomem;
@@ -434,7 +437,7 @@ static int uninorth_create_gatt_table(struct agp_bridge_data *bridge)
        return 0;
 
 enomem:
-       kfree(pages);
+       kfree(uninorth_priv.pages_arr);
        if (table)
                free_pages((unsigned long)table, page_order);
        return -ENOMEM;
@@ -456,6 +459,7 @@ static int uninorth_free_gatt_table(struct agp_bridge_data *bridge)
         */
 
        vunmap(bridge->gatt_table);
+       kfree(uninorth_priv.pages_arr);
        table = (char *) bridge->gatt_table_real;
        table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);