diff options
author | John Brooks <john.brooks@jolla.com> | 2015-03-24 16:54:17 -0400 |
---|---|---|
committer | Paul Moore <pmoore@redhat.com> | 2015-04-06 20:16:21 -0400 |
commit | 33ebc1932a07efd8728975750409741940334489 (patch) | |
tree | ce88911dbfbfa42b6cfd4c06631a25b74f94d53a /security/selinux/ss/avtab.c | |
parent | ba39db6e0519aa8362dbda6523ceb69349a18dc3 (diff) |
selinux: Use a better hash function for avtab
This function, based on murmurhash3, has much better distribution than
the original. Using the current default of 2048 buckets, there are many
fewer collisions:
Before:
101421 entries and 2048/2048 buckets used, longest chain length 374
After:
101421 entries and 2048/2048 buckets used, longest chain length 81
The difference becomes much more significant when buckets are increased.
A naive attempt to expand the current function to larger outputs doesn't
yield any significant improvement; so this function is a prerequisite
for increasing the bucket size.
sds: Adapted from the original patches for libsepol to the kernel.
Signed-off-by: John Brooks <john.brooks@jolla.com>
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: Paul Moore <pmoore@redhat.com>
Diffstat (limited to 'security/selinux/ss/avtab.c')
-rw-r--r-- | security/selinux/ss/avtab.c | 41 |
1 files changed, 37 insertions, 4 deletions
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index 3ea0198fc964..b64f2772b030 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c | |||
@@ -25,10 +25,43 @@ | |||
25 | 25 | ||
26 | static struct kmem_cache *avtab_node_cachep; | 26 | static struct kmem_cache *avtab_node_cachep; |
27 | 27 | ||
28 | static inline int avtab_hash(struct avtab_key *keyp, u16 mask) | 28 | /* Based on MurmurHash3, written by Austin Appleby and placed in the |
29 | * public domain. | ||
30 | */ | ||
31 | static inline int avtab_hash(struct avtab_key *keyp, u32 mask) | ||
29 | { | 32 | { |
30 | return ((keyp->target_class + (keyp->target_type << 2) + | 33 | static const u32 c1 = 0xcc9e2d51; |
31 | (keyp->source_type << 9)) & mask); | 34 | static const u32 c2 = 0x1b873593; |
35 | static const u32 r1 = 15; | ||
36 | static const u32 r2 = 13; | ||
37 | static const u32 m = 5; | ||
38 | static const u32 n = 0xe6546b64; | ||
39 | |||
40 | u32 hash = 0; | ||
41 | |||
42 | #define mix(input) { \ | ||
43 | u32 v = input; \ | ||
44 | v *= c1; \ | ||
45 | v = (v << r1) | (v >> (32 - r1)); \ | ||
46 | v *= c2; \ | ||
47 | hash ^= v; \ | ||
48 | hash = (hash << r2) | (hash >> (32 - r2)); \ | ||
49 | hash = hash * m + n; \ | ||
50 | } | ||
51 | |||
52 | mix(keyp->target_class); | ||
53 | mix(keyp->target_type); | ||
54 | mix(keyp->source_type); | ||
55 | |||
56 | #undef mix | ||
57 | |||
58 | hash ^= hash >> 16; | ||
59 | hash *= 0x85ebca6b; | ||
60 | hash ^= hash >> 13; | ||
61 | hash *= 0xc2b2ae35; | ||
62 | hash ^= hash >> 16; | ||
63 | |||
64 | return hash & mask; | ||
32 | } | 65 | } |
33 | 66 | ||
34 | static struct avtab_node* | 67 | static struct avtab_node* |
@@ -256,7 +289,7 @@ int avtab_init(struct avtab *h) | |||
256 | 289 | ||
257 | int avtab_alloc(struct avtab *h, u32 nrules) | 290 | int avtab_alloc(struct avtab *h, u32 nrules) |
258 | { | 291 | { |
259 | u16 mask = 0; | 292 | u32 mask = 0; |
260 | u32 shift = 0; | 293 | u32 shift = 0; |
261 | u32 work = nrules; | 294 | u32 work = nrules; |
262 | u32 nslot = 0; | 295 | u32 nslot = 0; |