1 From dd336c554d8926c3348a2d5f2a5ef5597f6d1a06 Mon Sep 17 00:00:00 2001
2 From: David Woodhouse <David.Woodhouse@intel.com>
3 Date: Sun, 2 May 2010 11:21:21 +0300
4 Subject: firmware_class: fix memory leak - free allocated pages
6 From: David Woodhouse <David.Woodhouse@intel.com>
8 commit dd336c554d8926c3348a2d5f2a5ef5597f6d1a06 upstream.
10 fix memory leak introduced by the patch 6e03a201bbe:
11 firmware: speed up request_firmware()
13 1. vfree won't release pages there were allocated explicitly and mapped
14 using vmap. The memory has to be vunmap-ed and the pages needs
15 to be freed explicitly
17 2. page array is moved into the 'struct
18 firmware' so that we can free it from release_firmware()
19 and not only in fw_dev_release()
21 The fix doesn't break the firmware load speed.
23 Cc: Johannes Berg <johannes@sipsolutions.net>
24 Cc: Ming Lei <tom.leiming@gmail.com>
25 Cc: Catalin Marinas <catalin.marinas@arm.com>
26 Singed-off-by: Kay Sievers <kay.sievers@vrfy.org>
27 Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
28 Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
29 Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
32 drivers/base/firmware_class.c | 26 ++++++++++++++++++++------
33 include/linux/firmware.h | 1 +
34 2 files changed, 21 insertions(+), 6 deletions(-)
36 --- a/drivers/base/firmware_class.c
37 +++ b/drivers/base/firmware_class.c
38 @@ -125,6 +125,17 @@ static ssize_t firmware_loading_show(str
39 return sprintf(buf, "%d\n", loading);
42 +static void firmware_free_data(const struct firmware *fw)
47 + for (i = 0; i < PFN_UP(fw->size); i++)
48 + __free_page(fw->pages[i]);
53 /* Some architectures don't have PAGE_KERNEL_RO */
54 #ifndef PAGE_KERNEL_RO
55 #define PAGE_KERNEL_RO PAGE_KERNEL
56 @@ -157,21 +168,21 @@ static ssize_t firmware_loading_store(st
57 mutex_unlock(&fw_lock);
60 - vfree(fw_priv->fw->data);
61 - fw_priv->fw->data = NULL;
62 + firmware_free_data(fw_priv->fw);
63 + memset(fw_priv->fw, 0, sizeof(struct firmware));
64 + /* If the pages are not owned by 'struct firmware' */
65 for (i = 0; i < fw_priv->nr_pages; i++)
66 __free_page(fw_priv->pages[i]);
67 kfree(fw_priv->pages);
68 fw_priv->pages = NULL;
69 fw_priv->page_array_size = 0;
70 fw_priv->nr_pages = 0;
71 - fw_priv->fw->size = 0;
72 set_bit(FW_STATUS_LOADING, &fw_priv->status);
73 mutex_unlock(&fw_lock);
76 if (test_bit(FW_STATUS_LOADING, &fw_priv->status)) {
77 - vfree(fw_priv->fw->data);
78 + vunmap(fw_priv->fw->data);
79 fw_priv->fw->data = vmap(fw_priv->pages,
82 @@ -179,7 +190,10 @@ static ssize_t firmware_loading_store(st
83 dev_err(dev, "%s: vmap() failed\n", __func__);
86 - /* Pages will be freed by vfree() */
87 + /* Pages are now owned by 'struct firmware' */
88 + fw_priv->fw->pages = fw_priv->pages;
89 + fw_priv->pages = NULL;
91 fw_priv->page_array_size = 0;
92 fw_priv->nr_pages = 0;
93 complete(&fw_priv->completion);
94 @@ -572,7 +586,7 @@ release_firmware(const struct firmware *
95 if (fw->data == builtin->data)
99 + firmware_free_data(fw);
103 --- a/include/linux/firmware.h
104 +++ b/include/linux/firmware.h
109 + struct page **pages;