aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/openrisc/include/asm/Kbuild1
-rw-r--r--arch/sparc/include/asm/Kbuild1
-rw-r--r--arch/x86/include/asm/word-at-a-time.h32
-rw-r--r--fs/namei.c22
-rw-r--r--include/asm-generic/word-at-a-time.h52
-rw-r--r--lib/strncpy_from_user.c47
6 files changed, 102 insertions, 53 deletions
diff --git a/arch/openrisc/include/asm/Kbuild b/arch/openrisc/include/asm/Kbuild
index c936483bc8e2..3f35c38d7b64 100644
--- a/arch/openrisc/include/asm/Kbuild
+++ b/arch/openrisc/include/asm/Kbuild
@@ -66,3 +66,4 @@ generic-y += topology.h
66generic-y += types.h 66generic-y += types.h
67generic-y += ucontext.h 67generic-y += ucontext.h
68generic-y += user.h 68generic-y += user.h
69generic-y += word-at-a-time.h
diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild
index 2c2e38821f60..67f83e0a0d68 100644
--- a/arch/sparc/include/asm/Kbuild
+++ b/arch/sparc/include/asm/Kbuild
@@ -21,3 +21,4 @@ generic-y += div64.h
21generic-y += local64.h 21generic-y += local64.h
22generic-y += irq_regs.h 22generic-y += irq_regs.h
23generic-y += local.h 23generic-y += local.h
24generic-y += word-at-a-time.h
diff --git a/arch/x86/include/asm/word-at-a-time.h b/arch/x86/include/asm/word-at-a-time.h
index ae03facfadd6..5b238981542a 100644
--- a/arch/x86/include/asm/word-at-a-time.h
+++ b/arch/x86/include/asm/word-at-a-time.h
@@ -10,6 +10,11 @@
10 * bit count instruction, that might be better than the multiply 10 * bit count instruction, that might be better than the multiply
11 * and shift, for example. 11 * and shift, for example.
12 */ 12 */
13struct word_at_a_time {
14 const unsigned long one_bits, high_bits;
15};
16
17#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) }
13 18
14#ifdef CONFIG_64BIT 19#ifdef CONFIG_64BIT
15 20
@@ -37,10 +42,31 @@ static inline long count_masked_bytes(long mask)
37 42
38#endif 43#endif
39 44
40/* Return the high bit set in the first byte that is a zero */ 45/* Return nonzero if it has a zero */
41static inline unsigned long has_zero(unsigned long a) 46static inline unsigned long has_zero(unsigned long a, unsigned long *bits, const struct word_at_a_time *c)
47{
48 unsigned long mask = ((a - c->one_bits) & ~a) & c->high_bits;
49 *bits = mask;
50 return mask;
51}
52
53static inline unsigned long prep_zero_mask(unsigned long a, unsigned long bits, const struct word_at_a_time *c)
54{
55 return bits;
56}
57
58static inline unsigned long create_zero_mask(unsigned long bits)
59{
60 bits = (bits - 1) & ~bits;
61 return bits >> 7;
62}
63
64/* The mask we created is directly usable as a bytemask */
65#define zero_bytemask(mask) (mask)
66
67static inline unsigned long find_zero(unsigned long mask)
42{ 68{
43 return ((a - REPEAT_BYTE(0x01)) & ~a) & REPEAT_BYTE(0x80); 69 return count_masked_bytes(mask);
44} 70}
45 71
46/* 72/*
diff --git a/fs/namei.c b/fs/namei.c
index 93ff12b1a1de..c651f02c9fec 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -1452,7 +1452,8 @@ EXPORT_SYMBOL(full_name_hash);
1452 */ 1452 */
1453static inline unsigned long hash_name(const char *name, unsigned int *hashp) 1453static inline unsigned long hash_name(const char *name, unsigned int *hashp)
1454{ 1454{
1455 unsigned long a, mask, hash, len; 1455 unsigned long a, b, adata, bdata, mask, hash, len;
1456 const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
1456 1457
1457 hash = a = 0; 1458 hash = a = 0;
1458 len = -sizeof(unsigned long); 1459 len = -sizeof(unsigned long);
@@ -1460,17 +1461,18 @@ static inline unsigned long hash_name(const char *name, unsigned int *hashp)
1460 hash = (hash + a) * 9; 1461 hash = (hash + a) * 9;
1461 len += sizeof(unsigned long); 1462 len += sizeof(unsigned long);
1462 a = load_unaligned_zeropad(name+len); 1463 a = load_unaligned_zeropad(name+len);
1463 /* Do we have any NUL or '/' bytes in this word? */ 1464 b = a ^ REPEAT_BYTE('/');
1464 mask = has_zero(a) | has_zero(a ^ REPEAT_BYTE('/')); 1465 } while (!(has_zero(a, &adata, &constants) | has_zero(b, &bdata, &constants)));
1465 } while (!mask); 1466
1466 1467 adata = prep_zero_mask(a, adata, &constants);
1467 /* The mask *below* the first high bit set */ 1468 bdata = prep_zero_mask(b, bdata, &constants);
1468 mask = (mask - 1) & ~mask; 1469
1469 mask >>= 7; 1470 mask = create_zero_mask(adata | bdata);
1470 hash += a & mask; 1471
1472 hash += a & zero_bytemask(mask);
1471 *hashp = fold_hash(hash); 1473 *hashp = fold_hash(hash);
1472 1474
1473 return len + count_masked_bytes(mask); 1475 return len + find_zero(mask);
1474} 1476}
1475 1477
1476#else 1478#else
diff --git a/include/asm-generic/word-at-a-time.h b/include/asm-generic/word-at-a-time.h
new file mode 100644
index 000000000000..3f21f1b72e45
--- /dev/null
+++ b/include/asm-generic/word-at-a-time.h
@@ -0,0 +1,52 @@
1#ifndef _ASM_WORD_AT_A_TIME_H
2#define _ASM_WORD_AT_A_TIME_H
3
4/*
5 * This says "generic", but it's actually big-endian only.
6 * Little-endian can use more efficient versions of these
7 * interfaces, see for example
8 * arch/x86/include/asm/word-at-a-time.h
9 * for those.
10 */
11
12#include <linux/kernel.h>
13
14struct word_at_a_time {
15 const unsigned long high_bits, low_bits;
16};
17
18#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0xfe) + 1, REPEAT_BYTE(0x7f) }
19
20/* Bit set in the bytes that have a zero */
21static inline long prep_zero_mask(unsigned long val, unsigned long rhs, const struct word_at_a_time *c)
22{
23 unsigned long mask = (val & c->low_bits) + c->low_bits;
24 return ~(mask | rhs);
25}
26
27#define create_zero_mask(mask) (mask)
28
29static inline long find_zero(unsigned long mask)
30{
31 long byte = 0;
32#ifdef CONFIG_64BIT
33 if (mask >> 32)
34 mask >>= 32;
35 else
36 byte = 4;
37#endif
38 if (mask >> 16)
39 mask >>= 16;
40 else
41 byte += 2;
42 return (mask >> 8) ? byte : byte + 1;
43}
44
45static inline bool has_zero(unsigned long val, unsigned long *data, const struct word_at_a_time *c)
46{
47 unsigned long rhs = val | c->low_bits;
48 *data = rhs;
49 return (val + c->high_bits) & ~rhs;
50}
51
52#endif /* _ASM_WORD_AT_A_TIME_H */
diff --git a/lib/strncpy_from_user.c b/lib/strncpy_from_user.c
index c4c09b0e96ba..bb2b201d6ad0 100644
--- a/lib/strncpy_from_user.c
+++ b/lib/strncpy_from_user.c
@@ -4,37 +4,7 @@
4#include <linux/errno.h> 4#include <linux/errno.h>
5 5
6#include <asm/byteorder.h> 6#include <asm/byteorder.h>
7 7#include <asm/word-at-a-time.h>
8static inline long find_zero(unsigned long mask)
9{
10 long byte = 0;
11
12#ifdef __BIG_ENDIAN
13#ifdef CONFIG_64BIT
14 if (mask >> 32)
15 mask >>= 32;
16 else
17 byte = 4;
18#endif
19 if (mask >> 16)
20 mask >>= 16;
21 else
22 byte += 2;
23 return (mask >> 8) ? byte : byte + 1;
24#else
25#ifdef CONFIG_64BIT
26 if (!((unsigned int) mask)) {
27 mask >>= 32;
28 byte = 4;
29 }
30#endif
31 if (!(mask & 0xffff)) {
32 mask >>= 16;
33 byte += 2;
34 }
35 return (mask & 0xff) ? byte : byte + 1;
36#endif
37}
38 8
39#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 9#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
40#define IS_UNALIGNED(src, dst) 0 10#define IS_UNALIGNED(src, dst) 0
@@ -51,8 +21,7 @@ static inline long find_zero(unsigned long mask)
51 */ 21 */
52static inline long do_strncpy_from_user(char *dst, const char __user *src, long count, unsigned long max) 22static inline long do_strncpy_from_user(char *dst, const char __user *src, long count, unsigned long max)
53{ 23{
54 const unsigned long high_bits = REPEAT_BYTE(0xfe) + 1; 24 const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
55 const unsigned long low_bits = REPEAT_BYTE(0x7f);
56 long res = 0; 25 long res = 0;
57 26
58 /* 27 /*
@@ -66,18 +35,16 @@ static inline long do_strncpy_from_user(char *dst, const char __user *src, long
66 goto byte_at_a_time; 35 goto byte_at_a_time;
67 36
68 while (max >= sizeof(unsigned long)) { 37 while (max >= sizeof(unsigned long)) {
69 unsigned long c, v, rhs; 38 unsigned long c, data;
70 39
71 /* Fall back to byte-at-a-time if we get a page fault */ 40 /* Fall back to byte-at-a-time if we get a page fault */
72 if (unlikely(__get_user(c,(unsigned long __user *)(src+res)))) 41 if (unlikely(__get_user(c,(unsigned long __user *)(src+res))))
73 break; 42 break;
74 rhs = c | low_bits;
75 v = (c + high_bits) & ~rhs;
76 *(unsigned long *)(dst+res) = c; 43 *(unsigned long *)(dst+res) = c;
77 if (v) { 44 if (has_zero(c, &data, &constants)) {
78 v = (c & low_bits) + low_bits; 45 data = prep_zero_mask(c, data, &constants);
79 v = ~(v | rhs); 46 data = create_zero_mask(data);
80 return res + find_zero(v); 47 return res + find_zero(data);
81 } 48 }
82 res += sizeof(unsigned long); 49 res += sizeof(unsigned long);
83 max -= sizeof(unsigned long); 50 max -= sizeof(unsigned long);