diff options
author | George Spelvin <linux@horizon.com> | 2016-05-02 06:31:01 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-16 14:35:08 -0400 |
commit | 0fed3ac866eabf01924457921ee3684c8e4c9005 (patch) | |
tree | d32e64a6c0dbe6f93e5345caec509cc580db2a37 /fs/namei.c | |
parent | 2dcd0af568b0cf583645c8a317dd12e344b1c72a (diff) |
namei: Improve hash mixing if CONFIG_DCACHE_WORD_ACCESS
The hash mixing between adding the next 64 bits of name
was just a bit weak.
Replaced with a still very fast but slightly more effective
mixing function.
Signed-off-by: George Spelvin <linux@horizon.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 33 |
1 files changed, 26 insertions, 7 deletions
diff --git a/fs/namei.c b/fs/namei.c index 30145f8f21ed..42f8ca038254 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1794,30 +1794,49 @@ static inline unsigned int fold_hash(unsigned long hash) | |||
1794 | return hash_64(hash, 32); | 1794 | return hash_64(hash, 32); |
1795 | } | 1795 | } |
1796 | 1796 | ||
1797 | /* | ||
1798 | * This is George Marsaglia's XORSHIFT generator. | ||
1799 | * It implements a maximum-period LFSR in only a few | ||
1800 | * instructions. It also has the property (required | ||
1801 | * by hash_name()) that mix_hash(0) = 0. | ||
1802 | */ | ||
1803 | static inline unsigned long mix_hash(unsigned long hash) | ||
1804 | { | ||
1805 | hash ^= hash << 13; | ||
1806 | hash ^= hash >> 7; | ||
1807 | hash ^= hash << 17; | ||
1808 | return hash; | ||
1809 | } | ||
1810 | |||
1797 | #else /* 32-bit case */ | 1811 | #else /* 32-bit case */ |
1798 | 1812 | ||
1799 | #define fold_hash(x) (x) | 1813 | #define fold_hash(x) (x) |
1800 | 1814 | ||
1815 | static inline unsigned long mix_hash(unsigned long hash) | ||
1816 | { | ||
1817 | hash ^= hash << 13; | ||
1818 | hash ^= hash >> 17; | ||
1819 | hash ^= hash << 5; | ||
1820 | return hash; | ||
1821 | } | ||
1822 | |||
1801 | #endif | 1823 | #endif |
1802 | 1824 | ||
1803 | unsigned int full_name_hash(const unsigned char *name, unsigned int len) | 1825 | unsigned int full_name_hash(const unsigned char *name, unsigned int len) |
1804 | { | 1826 | { |
1805 | unsigned long a, mask; | 1827 | unsigned long a, hash = 0; |
1806 | unsigned long hash = 0; | ||
1807 | 1828 | ||
1808 | for (;;) { | 1829 | for (;;) { |
1809 | a = load_unaligned_zeropad(name); | 1830 | a = load_unaligned_zeropad(name); |
1810 | if (len < sizeof(unsigned long)) | 1831 | if (len < sizeof(unsigned long)) |
1811 | break; | 1832 | break; |
1812 | hash += a; | 1833 | hash = mix_hash(hash + a); |
1813 | hash *= 9; | ||
1814 | name += sizeof(unsigned long); | 1834 | name += sizeof(unsigned long); |
1815 | len -= sizeof(unsigned long); | 1835 | len -= sizeof(unsigned long); |
1816 | if (!len) | 1836 | if (!len) |
1817 | goto done; | 1837 | goto done; |
1818 | } | 1838 | } |
1819 | mask = bytemask_from_count(len); | 1839 | hash += a & bytemask_from_count(len); |
1820 | hash += mask & a; | ||
1821 | done: | 1840 | done: |
1822 | return fold_hash(hash); | 1841 | return fold_hash(hash); |
1823 | } | 1842 | } |
@@ -1835,7 +1854,7 @@ static inline u64 hash_name(const char *name) | |||
1835 | hash = a = 0; | 1854 | hash = a = 0; |
1836 | len = -sizeof(unsigned long); | 1855 | len = -sizeof(unsigned long); |
1837 | do { | 1856 | do { |
1838 | hash = (hash + a) * 9; | 1857 | hash = mix_hash(hash + a); |
1839 | len += sizeof(unsigned long); | 1858 | len += sizeof(unsigned long); |
1840 | a = load_unaligned_zeropad(name+len); | 1859 | a = load_unaligned_zeropad(name+len); |
1841 | b = a ^ REPEAT_BYTE('/'); | 1860 | b = a ^ REPEAT_BYTE('/'); |