]>
Commit | Line | Data |
---|---|---|
3b04b1f3 JR |
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 | ||
2380c486 JR |
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) |