aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Vosburgh <jay.vosburgh@canonical.com>2014-11-14 14:05:06 -0500
committerDavid S. Miller <davem@davemloft.net>2014-11-14 16:36:25 -0500
commita77f9c5dcdf8480a93332792c336fa2bf9d31229 (patch)
tree003964de0cc772f361d254385406fa75f3fcbff2
parent8cd4313aa775537f724486d5b7503b4d46c9f012 (diff)
Revert "fast_hash: avoid indirect function calls"
This reverts commit e5a2c899957659cd1a9f789bc462f9c0b35f5150. Commit e5a2c899 introduced an alternative_call, arch_fast_hash2, that selects between __jhash2 and __intel_crc4_2_hash based on the X86_FEATURE_XMM4_2. Unfortunately, the alternative_call system does not appear to be suitable for use with C functions, as register usage is not handled properly for the called functions. The __jhash2 function in particular clobbers registers that are not preserved when called via alternative_call, resulting in a panic for direct callers of arch_fast_hash2 on older CPUs lacking sse4_2. It is possible that __intel_crc4_2_hash works merely by chance because it uses fewer registers. This commit was suggested as the source of the problem by Jesse Gross <jesse@nicira.com>. Signed-off-by: Jay Vosburgh <jay.vosburgh@canonical.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--arch/x86/include/asm/hash.h51
-rw-r--r--arch/x86/lib/hash.c29
-rw-r--r--include/asm-generic/hash.h36
-rw-r--r--include/linux/hash.h34
-rw-r--r--lib/Makefile2
-rw-r--r--lib/hash.c39
6 files changed, 93 insertions, 98 deletions
diff --git a/arch/x86/include/asm/hash.h b/arch/x86/include/asm/hash.h
index a881d784f044..e8c58f88b1d4 100644
--- a/arch/x86/include/asm/hash.h
+++ b/arch/x86/include/asm/hash.h
@@ -1,48 +1,7 @@
1#ifndef __ASM_X86_HASH_H 1#ifndef _ASM_X86_HASH_H
2#define __ASM_X86_HASH_H 2#define _ASM_X86_HASH_H
3 3
4#include <linux/cpufeature.h> 4struct fast_hash_ops;
5#include <asm/alternative.h> 5extern void setup_arch_fast_hash(struct fast_hash_ops *ops);
6 6
7u32 __intel_crc4_2_hash(const void *data, u32 len, u32 seed); 7#endif /* _ASM_X86_HASH_H */
8u32 __intel_crc4_2_hash2(const u32 *data, u32 len, u32 seed);
9
10/*
11 * non-inline versions of jhash so gcc does not need to generate
12 * duplicate code in every object file
13 */
14u32 __jhash(const void *data, u32 len, u32 seed);
15u32 __jhash2(const u32 *data, u32 len, u32 seed);
16
17/*
18 * for documentation of these functions please look into
19 * <include/asm-generic/hash.h>
20 */
21
22static inline u32 arch_fast_hash(const void *data, u32 len, u32 seed)
23{
24 u32 hash;
25
26 alternative_call(__jhash, __intel_crc4_2_hash, X86_FEATURE_XMM4_2,
27#ifdef CONFIG_X86_64
28 "=a" (hash), "D" (data), "S" (len), "d" (seed));
29#else
30 "=a" (hash), "a" (data), "d" (len), "c" (seed));
31#endif
32 return hash;
33}
34
35static inline u32 arch_fast_hash2(const u32 *data, u32 len, u32 seed)
36{
37 u32 hash;
38
39 alternative_call(__jhash2, __intel_crc4_2_hash2, X86_FEATURE_XMM4_2,
40#ifdef CONFIG_X86_64
41 "=a" (hash), "D" (data), "S" (len), "d" (seed));
42#else
43 "=a" (hash), "a" (data), "d" (len), "c" (seed));
44#endif
45 return hash;
46}
47
48#endif /* __ASM_X86_HASH_H */
diff --git a/arch/x86/lib/hash.c b/arch/x86/lib/hash.c
index e14327198835..ff4fa51a5b1f 100644
--- a/arch/x86/lib/hash.c
+++ b/arch/x86/lib/hash.c
@@ -31,13 +31,13 @@
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */ 32 */
33 33
34#include <linux/hash.h>
35#include <linux/init.h>
36
34#include <asm/processor.h> 37#include <asm/processor.h>
35#include <asm/cpufeature.h> 38#include <asm/cpufeature.h>
36#include <asm/hash.h> 39#include <asm/hash.h>
37 40
38#include <linux/hash.h>
39#include <linux/jhash.h>
40
41static inline u32 crc32_u32(u32 crc, u32 val) 41static inline u32 crc32_u32(u32 crc, u32 val)
42{ 42{
43#ifdef CONFIG_AS_CRC32 43#ifdef CONFIG_AS_CRC32
@@ -48,7 +48,7 @@ static inline u32 crc32_u32(u32 crc, u32 val)
48 return crc; 48 return crc;
49} 49}
50 50
51u32 __intel_crc4_2_hash(const void *data, u32 len, u32 seed) 51static u32 intel_crc4_2_hash(const void *data, u32 len, u32 seed)
52{ 52{
53 const u32 *p32 = (const u32 *) data; 53 const u32 *p32 = (const u32 *) data;
54 u32 i, tmp = 0; 54 u32 i, tmp = 0;
@@ -71,27 +71,22 @@ u32 __intel_crc4_2_hash(const void *data, u32 len, u32 seed)
71 71
72 return seed; 72 return seed;
73} 73}
74EXPORT_SYMBOL(__intel_crc4_2_hash);
75 74
76u32 __intel_crc4_2_hash2(const u32 *data, u32 len, u32 seed) 75static u32 intel_crc4_2_hash2(const u32 *data, u32 len, u32 seed)
77{ 76{
77 const u32 *p32 = (const u32 *) data;
78 u32 i; 78 u32 i;
79 79
80 for (i = 0; i < len; i++) 80 for (i = 0; i < len; i++)
81 seed = crc32_u32(seed, *data++); 81 seed = crc32_u32(seed, *p32++);
82 82
83 return seed; 83 return seed;
84} 84}
85EXPORT_SYMBOL(__intel_crc4_2_hash2);
86 85
87u32 __jhash(const void *data, u32 len, u32 seed) 86void __init setup_arch_fast_hash(struct fast_hash_ops *ops)
88{ 87{
89 return jhash(data, len, seed); 88 if (cpu_has_xmm4_2) {
90} 89 ops->hash = intel_crc4_2_hash;
91EXPORT_SYMBOL(__jhash); 90 ops->hash2 = intel_crc4_2_hash2;
92 91 }
93u32 __jhash2(const u32 *data, u32 len, u32 seed)
94{
95 return jhash2(data, len, seed);
96} 92}
97EXPORT_SYMBOL(__jhash2);
diff --git a/include/asm-generic/hash.h b/include/asm-generic/hash.h
index 3c82760ff2a4..b6312843dbd9 100644
--- a/include/asm-generic/hash.h
+++ b/include/asm-generic/hash.h
@@ -1,41 +1,9 @@
1#ifndef __ASM_GENERIC_HASH_H 1#ifndef __ASM_GENERIC_HASH_H
2#define __ASM_GENERIC_HASH_H 2#define __ASM_GENERIC_HASH_H
3 3
4#include <linux/jhash.h> 4struct fast_hash_ops;
5 5static inline void setup_arch_fast_hash(struct fast_hash_ops *ops)
6/**
7 * arch_fast_hash - Caclulates a hash over a given buffer that can have
8 * arbitrary size. This function will eventually use an
9 * architecture-optimized hashing implementation if
10 * available, and trades off distribution for speed.
11 *
12 * @data: buffer to hash
13 * @len: length of buffer in bytes
14 * @seed: start seed
15 *
16 * Returns 32bit hash.
17 */
18static inline u32 arch_fast_hash(const void *data, u32 len, u32 seed)
19{
20 return jhash(data, len, seed);
21}
22
23/**
24 * arch_fast_hash2 - Caclulates a hash over a given buffer that has a
25 * size that is of a multiple of 32bit words. This
26 * function will eventually use an architecture-
27 * optimized hashing implementation if available,
28 * and trades off distribution for speed.
29 *
30 * @data: buffer to hash (must be 32bit padded)
31 * @len: number of 32bit words
32 * @seed: start seed
33 *
34 * Returns 32bit hash.
35 */
36static inline u32 arch_fast_hash2(const u32 *data, u32 len, u32 seed)
37{ 6{
38 return jhash2(data, len, seed);
39} 7}
40 8
41#endif /* __ASM_GENERIC_HASH_H */ 9#endif /* __ASM_GENERIC_HASH_H */
diff --git a/include/linux/hash.h b/include/linux/hash.h
index 6e8fb028848c..d0494c399392 100644
--- a/include/linux/hash.h
+++ b/include/linux/hash.h
@@ -84,4 +84,38 @@ static inline u32 hash32_ptr(const void *ptr)
84 return (u32)val; 84 return (u32)val;
85} 85}
86 86
87struct fast_hash_ops {
88 u32 (*hash)(const void *data, u32 len, u32 seed);
89 u32 (*hash2)(const u32 *data, u32 len, u32 seed);
90};
91
92/**
93 * arch_fast_hash - Caclulates a hash over a given buffer that can have
94 * arbitrary size. This function will eventually use an
95 * architecture-optimized hashing implementation if
96 * available, and trades off distribution for speed.
97 *
98 * @data: buffer to hash
99 * @len: length of buffer in bytes
100 * @seed: start seed
101 *
102 * Returns 32bit hash.
103 */
104extern u32 arch_fast_hash(const void *data, u32 len, u32 seed);
105
106/**
107 * arch_fast_hash2 - Caclulates a hash over a given buffer that has a
108 * size that is of a multiple of 32bit words. This
109 * function will eventually use an architecture-
110 * optimized hashing implementation if available,
111 * and trades off distribution for speed.
112 *
113 * @data: buffer to hash (must be 32bit padded)
114 * @len: number of 32bit words
115 * @seed: start seed
116 *
117 * Returns 32bit hash.
118 */
119extern u32 arch_fast_hash2(const u32 *data, u32 len, u32 seed);
120
87#endif /* _LINUX_HASH_H */ 121#endif /* _LINUX_HASH_H */
diff --git a/lib/Makefile b/lib/Makefile
index 04e53dd16070..7512dc978f18 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -26,7 +26,7 @@ obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
26 bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \ 26 bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \
27 gcd.o lcm.o list_sort.o uuid.o flex_array.o iovec.o clz_ctz.o \ 27 gcd.o lcm.o list_sort.o uuid.o flex_array.o iovec.o clz_ctz.o \
28 bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o kfifo.o \ 28 bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o kfifo.o \
29 percpu-refcount.o percpu_ida.o rhashtable.o 29 percpu-refcount.o percpu_ida.o hash.o rhashtable.o
30obj-y += string_helpers.o 30obj-y += string_helpers.o
31obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o 31obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o
32obj-y += kstrtox.o 32obj-y += kstrtox.o
diff --git a/lib/hash.c b/lib/hash.c
new file mode 100644
index 000000000000..fea973f4bd57
--- /dev/null
+++ b/lib/hash.c
@@ -0,0 +1,39 @@
1/* General purpose hashing library
2 *
3 * That's a start of a kernel hashing library, which can be extended
4 * with further algorithms in future. arch_fast_hash{2,}() will
5 * eventually resolve to an architecture optimized implementation.
6 *
7 * Copyright 2013 Francesco Fusco <ffusco@redhat.com>
8 * Copyright 2013 Daniel Borkmann <dborkman@redhat.com>
9 * Copyright 2013 Thomas Graf <tgraf@redhat.com>
10 * Licensed under the GNU General Public License, version 2.0 (GPLv2)
11 */
12
13#include <linux/jhash.h>
14#include <linux/hash.h>
15#include <linux/cache.h>
16
17static struct fast_hash_ops arch_hash_ops __read_mostly = {
18 .hash = jhash,
19 .hash2 = jhash2,
20};
21
22u32 arch_fast_hash(const void *data, u32 len, u32 seed)
23{
24 return arch_hash_ops.hash(data, len, seed);
25}
26EXPORT_SYMBOL_GPL(arch_fast_hash);
27
28u32 arch_fast_hash2(const u32 *data, u32 len, u32 seed)
29{
30 return arch_hash_ops.hash2(data, len, seed);
31}
32EXPORT_SYMBOL_GPL(arch_fast_hash2);
33
34static int __init hashlib_init(void)
35{
36 setup_arch_fast_hash(&arch_hash_ops);
37 return 0;
38}
39early_initcall(hashlib_init);