]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/2.6.32.17/firmware_class-fix-memory-leak-free-allocated-pages.patch
4.9-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 2.6.32.17 / firmware_class-fix-memory-leak-free-allocated-pages.patch
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
5
6 From: David Woodhouse <David.Woodhouse@intel.com>
7
8 commit dd336c554d8926c3348a2d5f2a5ef5597f6d1a06 upstream.
9
10 fix memory leak introduced by the patch 6e03a201bbe:
11 firmware: speed up request_firmware()
12
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
16
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()
20
21 The fix doesn't break the firmware load speed.
22
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>
30
31 ---
32 drivers/base/firmware_class.c | 26 ++++++++++++++++++++------
33 include/linux/firmware.h | 1 +
34 2 files changed, 21 insertions(+), 6 deletions(-)
35
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);
40 }
41
42 +static void firmware_free_data(const struct firmware *fw)
43 +{
44 + int i;
45 + vunmap(fw->data);
46 + if (fw->pages) {
47 + for (i = 0; i < PFN_UP(fw->size); i++)
48 + __free_page(fw->pages[i]);
49 + kfree(fw->pages);
50 + }
51 +}
52 +
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);
58 break;
59 }
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);
74 break;
75 case 0:
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,
80 fw_priv->nr_pages,
81 0, PAGE_KERNEL_RO);
82 @@ -179,7 +190,10 @@ static ssize_t firmware_loading_store(st
83 dev_err(dev, "%s: vmap() failed\n", __func__);
84 goto err;
85 }
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;
90 +
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)
96 goto free_fw;
97 }
98 - vfree(fw->data);
99 + firmware_free_data(fw);
100 free_fw:
101 kfree(fw);
102 }
103 --- a/include/linux/firmware.h
104 +++ b/include/linux/firmware.h
105 @@ -11,6 +11,7 @@
106 struct firmware {
107 size_t size;
108 const u8 *data;
109 + struct page **pages;
110 };
111
112 struct device;