]>
Commit | Line | Data |
---|---|---|
1 | rom ae060e0b7bc071bd73dd5319b93c3344d9e10212 Mon Sep 17 00:00:00 2001 | |
2 | From: Manfred Spraul <manfred@colorfullife.com> | |
3 | To: torvalds@linux-foundation.org | |
4 | Cc: linux-kernel@vger.kernel.org | |
5 | Cc: cebbert@redhat.com | |
6 | Cc: airlied@gmail.com | |
7 | Cc: akpm@linux-foundation.org | |
8 | Bcc: manfred@colorfullife.com | |
9 | Date: Wed, 10 Dec 2008 18:17:06 +0100 | |
10 | Subject: [PATCH] lib/idr.c: Fix bug introduced by RCU fix | |
11 | ||
12 | The last patch to lib/idr.c caused a bug if idr_get_new_above() was | |
13 | called on an empty idr: | |
14 | Usually, nodes stay on the same layer. New layers are added to the top | |
15 | of the tree. | |
16 | The exception is idr_get_new_above() on an empty tree: In this case, | |
17 | the new root node is first added on layer 0, then moved upwards. | |
18 | p->layer was not updated. | |
19 | ||
20 | As usual: You shall never rely on the source code comments, they | |
21 | will only mislead you. | |
22 | ||
23 | Signed-off-by: Manfred Spraul <manfred@colorfullife.com> | |
24 | --- | |
25 | lib/idr.c | 8 +++++++- | |
26 | 1 files changed, 7 insertions(+), 1 deletions(-) | |
27 | ||
28 | diff --git a/lib/idr.c b/lib/idr.c | |
29 | index 7a785a0..1c4f928 100644 | |
30 | --- a/lib/idr.c | |
31 | +++ b/lib/idr.c | |
32 | @@ -220,8 +220,14 @@ build_up: | |
33 | */ | |
34 | while ((layers < (MAX_LEVEL - 1)) && (id >= (1 << (layers*IDR_BITS)))) { | |
35 | layers++; | |
36 | - if (!p->count) | |
37 | + if (!p->count) { | |
38 | + /* special case: if the tree is currently empty, | |
39 | + * then we grow the tree by moving the top node | |
40 | + * upwards. | |
41 | + */ | |
42 | + p->layer++; | |
43 | continue; | |
44 | + } | |
45 | if (!(new = get_from_free_list(idp))) { | |
46 | /* | |
47 | * The allocation failed. If we built part of | |
48 | -- | |
49 | 1.5.6.5 | |
50 | ||
51 | From: Trond Myklebust <Trond.Myklebust@netapp.com> | |
52 | Date: Thu, 20 Nov 2008 21:06:21 +0000 (-0500) | |
53 | Subject: SUNRPC: Fix a performance regression in the RPC authentication code | |
54 | X-Git-Tag: v2.6.28-rc6~4 | |
55 | X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=23918b03060f6e572168fdde1798a905679d2e06 | |
56 | ||
57 | SUNRPC: Fix a performance regression in the RPC authentication code | |
58 | ||
59 | Fix a regression reported by Max Kellermann whereby kernel profiling | |
60 | showed that his clients were spending 45% of their time in | |
61 | rpcauth_lookup_credcache. | |
62 | ||
63 | It turns out that although his processes had identical uid/gid/groups, | |
64 | generic_match() was failing to detect this, because the task->group_info | |
65 | pointers were not shared. This again lead to the creation of a huge number | |
66 | of identical credentials at the RPC layer. | |
67 | ||
68 | The regression is fixed by comparing the contents of task->group_info | |
69 | if the actual pointers are not identical. | |
70 | ||
71 | Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> | |
72 | Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> | |
73 | --- | |
74 | ||
75 | diff --git a/net/sunrpc/auth_generic.c b/net/sunrpc/auth_generic.c | |
76 | index 744b79f..4028502 100644 | |
77 | --- a/net/sunrpc/auth_generic.c | |
78 | +++ b/net/sunrpc/auth_generic.c | |
79 | @@ -133,13 +133,29 @@ static int | |
80 | generic_match(struct auth_cred *acred, struct rpc_cred *cred, int flags) | |
81 | { | |
82 | struct generic_cred *gcred = container_of(cred, struct generic_cred, gc_base); | |
83 | + int i; | |
84 | ||
85 | if (gcred->acred.uid != acred->uid || | |
86 | gcred->acred.gid != acred->gid || | |
87 | - gcred->acred.group_info != acred->group_info || | |
88 | gcred->acred.machine_cred != acred->machine_cred) | |
89 | - return 0; | |
90 | + goto out_nomatch; | |
91 | + | |
92 | + /* Optimisation in the case where pointers are identical... */ | |
93 | + if (gcred->acred.group_info == acred->group_info) | |
94 | + goto out_match; | |
95 | + | |
96 | + /* Slow path... */ | |
97 | + if (gcred->acred.group_info->ngroups != acred->group_info->ngroups) | |
98 | + goto out_nomatch; | |
99 | + for (i = 0; i < gcred->acred.group_info->ngroups; i++) { | |
100 | + if (GROUP_AT(gcred->acred.group_info, i) != | |
101 | + GROUP_AT(acred->group_info, i)) | |
102 | + goto out_nomatch; | |
103 | + } | |
104 | +out_match: | |
105 | return 1; | |
106 | +out_nomatch: | |
107 | + return 0; | |
108 | } | |
109 | ||
110 | void __init rpc_init_generic_auth(void) | |
111 | From d238e150805a0710fa626f9a7f65816aa15b741c Mon Sep 17 00:00:00 2001 | |
112 | From: Brian Rogers <brian@xyzw.org> | |
113 | Date: Fri, 4 Sep 2009 05:55:01 -0700 | |
114 | Subject: [PATCH] Fix memory corruption during IR initialization for various tuner cards | |
115 | ||
116 | In two different places the IR_i2c_init_data structure is used to store some | |
117 | data for particular cards that will later override the settings that would | |
118 | otherwise be used by the ir-kbd-i2c driver in ir_probe(). The way those | |
119 | settings get there is problematic: init_data is on the stack, and a pointer to | |
120 | it is stored to be used after the function that sets it up returns. Not good. | |
121 | ||
122 | init_data might be overwritten by the time ir_probe() runs. ir_probe() will | |
123 | then call ir_input_init(), which proceeds to fill out the dev->keybit bit | |
124 | array with a 1 in the appropriate slot for every key on the tuner's remote. | |
125 | ||
126 | But if the keymap pointer now points to random garbage, that will be used | |
127 | instead to determine where to write each 1. And since IR_KEYTAB_TYPE is u32, | |
128 | it can be write millions of bits past the end of dev->keybit. Essentially | |
129 | this bug writes a 1 to up to 128 random bits in memory, stopping early (and | |
130 | oopsing) if or when it hits an invalid page. | |
131 | ||
132 | To fix this, I define a static IR_i2c_init_data struct for each card that | |
133 | needs one rather than creating the data on the stack. This way, I can supply a | |
134 | pointer that will remain valid. Also I don't have to allocate memory just to | |
135 | store information that's already known at compile time and I don't have bother | |
136 | freeing it, either. | |
137 | ||
138 | This fixes a regression caused by commit 4d7a2d6721. | |
139 | ||
140 | Signed-off-by: Brian Rogers <brian@xyzw.org> | |
141 | --- | |
142 | drivers/media/video/em28xx/em28xx-cards.c | 36 +++++++++----- | |
143 | drivers/media/video/saa7134/saa7134-input.c | 71 ++++++++++++++++++--------- | |
144 | 2 files changed, 70 insertions(+), 37 deletions(-) | |
145 | ||
146 | diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c | |
147 | index 1c2e544..be9a4e8 100644 | |
148 | --- a/drivers/media/video/em28xx/em28xx-cards.c | |
149 | +++ b/drivers/media/video/em28xx/em28xx-cards.c | |
150 | @@ -2167,11 +2167,29 @@ static int em28xx_hint_board(struct em28xx *dev) | |
151 | return -1; | |
152 | } | |
153 | ||
154 | +static struct IR_i2c_init_data init_data_em28xx_terratec = { | |
155 | + .name = "i2c IR (EM28XX Terratec)", | |
156 | + .ir_codes = ir_codes_em_terratec, | |
157 | + .get_key = em28xx_get_key_terratec, | |
158 | +}; | |
159 | + | |
160 | +static struct IR_i2c_init_data init_data_em28xx_pinnacle = { | |
161 | + .name = "i2c IR (EM28XX Pinnacle PCTV)", | |
162 | + .ir_codes = ir_codes_pinnacle_grey, | |
163 | + .get_key = em28xx_get_key_pinnacle_usb_grey, | |
164 | +}; | |
165 | + | |
166 | +static struct IR_i2c_init_data init_data_em28xx_hauppauge = { | |
167 | + .name = "i2c IR (EM2840 Hauppauge)", | |
168 | + .ir_codes = ir_codes_hauppauge_new, | |
169 | + .get_key = em28xx_get_key_em_haup, | |
170 | +}; | |
171 | + | |
172 | /* ----------------------------------------------------------------------- */ | |
173 | void em28xx_register_i2c_ir(struct em28xx *dev) | |
174 | { | |
175 | struct i2c_board_info info; | |
176 | - struct IR_i2c_init_data init_data; | |
177 | + struct IR_i2c_init_data *init_data = NULL; | |
178 | const unsigned short addr_list[] = { | |
179 | 0x30, 0x47, I2C_CLIENT_END | |
180 | }; | |
181 | @@ -2180,7 +2198,6 @@ void em28xx_register_i2c_ir(struct em28xx *dev) | |
182 | return; | |
183 | ||
184 | memset(&info, 0, sizeof(struct i2c_board_info)); | |
185 | - memset(&init_data, 0, sizeof(struct IR_i2c_init_data)); | |
186 | strlcpy(info.type, "ir_video", I2C_NAME_SIZE); | |
187 | ||
188 | /* detect & configure */ | |
189 | @@ -2191,19 +2208,13 @@ void em28xx_register_i2c_ir(struct em28xx *dev) | |
190 | break; | |
191 | case (EM2800_BOARD_TERRATEC_CINERGY_200): | |
192 | case (EM2820_BOARD_TERRATEC_CINERGY_250): | |
193 | - init_data.ir_codes = ir_codes_em_terratec; | |
194 | - init_data.get_key = em28xx_get_key_terratec; | |
195 | - init_data.name = "i2c IR (EM28XX Terratec)"; | |
196 | + init_data = &init_data_em28xx_terratec; | |
197 | break; | |
198 | case (EM2820_BOARD_PINNACLE_USB_2): | |
199 | - init_data.ir_codes = ir_codes_pinnacle_grey; | |
200 | - init_data.get_key = em28xx_get_key_pinnacle_usb_grey; | |
201 | - init_data.name = "i2c IR (EM28XX Pinnacle PCTV)"; | |
202 | + init_data = &init_data_em28xx_pinnacle; | |
203 | break; | |
204 | case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2): | |
205 | - init_data.ir_codes = ir_codes_hauppauge_new; | |
206 | - init_data.get_key = em28xx_get_key_em_haup; | |
207 | - init_data.name = "i2c IR (EM2840 Hauppauge)"; | |
208 | + init_data = &init_data_em28xx_hauppauge; | |
209 | break; | |
210 | case (EM2820_BOARD_MSI_VOX_USB_2): | |
211 | break; | |
212 | @@ -2215,8 +2226,7 @@ void em28xx_register_i2c_ir(struct em28xx *dev) | |
213 | break; | |
214 | } | |
215 | ||
216 | - if (init_data.name) | |
217 | - info.platform_data = &init_data; | |
218 | + info.platform_data = init_data; | |
219 | i2c_new_probed_device(&dev->i2c_adap, &info, addr_list); | |
220 | } | |
221 | ||
222 | diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c | |
223 | index 6e219c2..bb17bb9 100644 | |
224 | --- a/drivers/media/video/saa7134/saa7134-input.c | |
225 | +++ b/drivers/media/video/saa7134/saa7134-input.c | |
226 | @@ -682,10 +682,46 @@ void saa7134_input_fini(struct saa7134_dev *dev) | |
227 | dev->remote = NULL; | |
228 | } | |
229 | ||
230 | +static struct IR_i2c_init_data init_data_pinnacle_color = { | |
231 | + .name = "Pinnacle PCTV", | |
232 | + .get_key = get_key_pinnacle_color, | |
233 | + .ir_codes = ir_codes_pinnacle_color, | |
234 | +}; | |
235 | + | |
236 | +static struct IR_i2c_init_data init_data_pinnacle_grey = { | |
237 | + .name = "Pinnacle PCTV", | |
238 | + .get_key = get_key_pinnacle_grey, | |
239 | + .ir_codes = ir_codes_pinnacle_grey, | |
240 | +}; | |
241 | + | |
242 | +static struct IR_i2c_init_data init_data_purpletv = { | |
243 | + .name = "Purple TV", | |
244 | + .get_key = get_key_purpletv, | |
245 | + .ir_codes = ir_codes_purpletv, | |
246 | +}; | |
247 | + | |
248 | +static struct IR_i2c_init_data init_data_msi_tvanywhere_plus = { | |
249 | + .name = "MSI TV@nywhere Plus", | |
250 | + .get_key = get_key_msi_tvanywhere_plus, | |
251 | + .ir_codes = ir_codes_msi_tvanywhere_plus, | |
252 | +}; | |
253 | + | |
254 | +static struct IR_i2c_init_data init_data_hauppauge = { | |
255 | + .name = "HVR 1110", | |
256 | + .get_key = get_key_hvr1110, | |
257 | + .ir_codes = ir_codes_hauppauge_new, | |
258 | +}; | |
259 | + | |
260 | +static struct IR_i2c_init_data init_data_behold = { | |
261 | + .name = "BeholdTV", | |
262 | + .get_key = get_key_beholdm6xx, | |
263 | + .ir_codes = ir_codes_behold, | |
264 | +}; | |
265 | + | |
266 | void saa7134_probe_i2c_ir(struct saa7134_dev *dev) | |
267 | { | |
268 | struct i2c_board_info info; | |
269 | - struct IR_i2c_init_data init_data; | |
270 | + struct IR_i2c_init_data *init_data = NULL; | |
271 | const unsigned short addr_list[] = { | |
272 | 0x7a, 0x47, 0x71, 0x2d, | |
273 | I2C_CLIENT_END | |
274 | @@ -706,30 +742,22 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev) | |
275 | } | |
276 | ||
277 | memset(&info, 0, sizeof(struct i2c_board_info)); | |
278 | - memset(&init_data, 0, sizeof(struct IR_i2c_init_data)); | |
279 | strlcpy(info.type, "ir_video", I2C_NAME_SIZE); | |
280 | ||
281 | switch (dev->board) { | |
282 | case SAA7134_BOARD_PINNACLE_PCTV_110i: | |
283 | case SAA7134_BOARD_PINNACLE_PCTV_310i: | |
284 | - init_data.name = "Pinnacle PCTV"; | |
285 | - if (pinnacle_remote == 0) { | |
286 | - init_data.get_key = get_key_pinnacle_color; | |
287 | - init_data.ir_codes = ir_codes_pinnacle_color; | |
288 | - } else { | |
289 | - init_data.get_key = get_key_pinnacle_grey; | |
290 | - init_data.ir_codes = ir_codes_pinnacle_grey; | |
291 | - } | |
292 | + if (pinnacle_remote == 0) | |
293 | + init_data = &init_data_pinnacle_color; | |
294 | + else | |
295 | + init_data = &init_data_pinnacle_grey; | |
296 | + info.addr = 0x47; | |
297 | break; | |
298 | case SAA7134_BOARD_UPMOST_PURPLE_TV: | |
299 | - init_data.name = "Purple TV"; | |
300 | - init_data.get_key = get_key_purpletv; | |
301 | - init_data.ir_codes = ir_codes_purpletv; | |
302 | + init_data = &init_data_purpletv; | |
303 | break; | |
304 | case SAA7134_BOARD_MSI_TVATANYWHERE_PLUS: | |
305 | - init_data.name = "MSI TV@nywhere Plus"; | |
306 | - init_data.get_key = get_key_msi_tvanywhere_plus; | |
307 | - init_data.ir_codes = ir_codes_msi_tvanywhere_plus; | |
308 | + init_data = &init_data_msi_tvanywhere_plus; | |
309 | info.addr = 0x30; | |
310 | /* MSI TV@nywhere Plus controller doesn't seem to | |
311 | respond to probes unless we read something from | |
312 | @@ -741,9 +769,7 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev) | |
313 | (1 == rc) ? "yes" : "no"); | |
314 | break; | |
315 | case SAA7134_BOARD_HAUPPAUGE_HVR1110: | |
316 | - init_data.name = "HVR 1110"; | |
317 | - init_data.get_key = get_key_hvr1110; | |
318 | - init_data.ir_codes = ir_codes_hauppauge_new; | |
319 | + init_data = &init_data_hauppauge; | |
320 | break; | |
321 | case SAA7134_BOARD_BEHOLD_607FM_MK3: | |
322 | case SAA7134_BOARD_BEHOLD_607FM_MK5: | |
323 | @@ -757,9 +783,7 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev) | |
324 | case SAA7134_BOARD_BEHOLD_M63: | |
325 | case SAA7134_BOARD_BEHOLD_M6_EXTRA: | |
326 | case SAA7134_BOARD_BEHOLD_H6: | |
327 | - init_data.name = "BeholdTV"; | |
328 | - init_data.get_key = get_key_beholdm6xx; | |
329 | - init_data.ir_codes = ir_codes_behold; | |
330 | + init_data = &init_data_behold; | |
331 | break; | |
332 | case SAA7134_BOARD_AVERMEDIA_CARDBUS_501: | |
333 | case SAA7134_BOARD_AVERMEDIA_CARDBUS_506: | |
334 | @@ -767,8 +791,7 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev) | |
335 | break; | |
336 | } | |
337 | ||
338 | - if (init_data.name) | |
339 | - info.platform_data = &init_data; | |
340 | + info.platform_data = init_data; | |
341 | /* No need to probe if address is known */ | |
342 | if (info.addr) { | |
343 | i2c_new_device(&dev->i2c_adap, &info); | |
344 | -- | |
345 | 1.6.3.3 | |
346 |