firmware: Free temporary page table after vmapping
authorTakashi Iwai <tiwai@suse.de>
Mon, 20 May 2019 09:26:43 +0000 (11:26 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 10 Jun 2019 17:20:36 +0000 (19:20 +0200)
Once after performing vmap() to map the S/G pages, our own page table
becomes superfluous since the pages can be released via vfree()
automatically.  Let's change the buffer release code and discard the
page table array for saving some memory.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/base/firmware_loader/fallback.c
drivers/base/firmware_loader/main.c

index f962488546b638e9cef66e0bb9cdd5326345fbd5..a0a1856aac84608d338b42dd79df4b047ec05e40 100644 (file)
@@ -222,7 +222,7 @@ static ssize_t firmware_loading_show(struct device *dev,
 /* one pages buffer should be mapped/unmapped only once */
 static int map_fw_priv_pages(struct fw_priv *fw_priv)
 {
-       if (!fw_priv->is_paged_buf)
+       if (!fw_priv->pages)
                return 0;
 
        vunmap(fw_priv->data);
@@ -230,6 +230,11 @@ static int map_fw_priv_pages(struct fw_priv *fw_priv)
                             PAGE_KERNEL_RO);
        if (!fw_priv->data)
                return -ENOMEM;
+
+       /* page table is no longer needed after mapping, let's free */
+       vfree(fw_priv->pages);
+       fw_priv->pages = NULL;
+
        return 0;
 }
 
index 7eaaf5ee5ba6ba618ab4114aec1a0be296722f1f..aed1a7c5671328edd1e5942f4e035d281d082416 100644 (file)
@@ -252,13 +252,13 @@ static void __free_fw_priv(struct kref *ref)
        spin_unlock(&fwc->lock);
 
 #ifdef CONFIG_FW_LOADER_USER_HELPER
-       if (fw_priv->is_paged_buf) {
+       if (fw_priv->pages) {
+               /* free leftover pages */
                int i;
-               vunmap(fw_priv->data);
                for (i = 0; i < fw_priv->nr_pages; i++)
                        __free_page(fw_priv->pages[i]);
                vfree(fw_priv->pages);
-       } else
+       }
 #endif
        if (!fw_priv->allocated_size)
                vfree(fw_priv->data);