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