diff options
author | Akinobu Mita <akinobu.mita@gmail.com> | 2011-10-31 20:08:07 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-31 20:30:47 -0400 |
commit | 798248206b59acc6e1238c778281419c041891a7 (patch) | |
tree | ff8564431367b442b18bca4a0a9732e5799e2391 /lib | |
parent | 77311139f364d7f71fc9ba88f59fd90e60205007 (diff) |
lib/string.c: introduce memchr_inv()
memchr_inv() is mainly used to check whether the whole buffer is filled
with just a specified byte.
The function name and prototype are stolen from logfs and the
implementation is from SLUB.
Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
Acked-by: Christoph Lameter <cl@linux-foundation.org>
Acked-by: Pekka Enberg <penberg@kernel.org>
Cc: Matt Mackall <mpm@selenic.com>
Acked-by: Joern Engel <joern@logfs.org>
Cc: Marcin Slusarz <marcin.slusarz@gmail.com>
Cc: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/string.c | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/lib/string.c b/lib/string.c index 01fad9b203e1..11df54325fb8 100644 --- a/lib/string.c +++ b/lib/string.c | |||
@@ -756,3 +756,57 @@ void *memchr(const void *s, int c, size_t n) | |||
756 | } | 756 | } |
757 | EXPORT_SYMBOL(memchr); | 757 | EXPORT_SYMBOL(memchr); |
758 | #endif | 758 | #endif |
759 | |||
760 | static void *check_bytes8(const u8 *start, u8 value, unsigned int bytes) | ||
761 | { | ||
762 | while (bytes) { | ||
763 | if (*start != value) | ||
764 | return (void *)start; | ||
765 | start++; | ||
766 | bytes--; | ||
767 | } | ||
768 | return NULL; | ||
769 | } | ||
770 | |||
771 | /** | ||
772 | * memchr_inv - Find an unmatching character in an area of memory. | ||
773 | * @start: The memory area | ||
774 | * @c: Find a character other than c | ||
775 | * @bytes: The size of the area. | ||
776 | * | ||
777 | * returns the address of the first character other than @c, or %NULL | ||
778 | * if the whole buffer contains just @c. | ||
779 | */ | ||
780 | void *memchr_inv(const void *start, int c, size_t bytes) | ||
781 | { | ||
782 | u8 value = c; | ||
783 | u64 value64; | ||
784 | unsigned int words, prefix; | ||
785 | |||
786 | if (bytes <= 16) | ||
787 | return check_bytes8(start, value, bytes); | ||
788 | |||
789 | value64 = value | value << 8 | value << 16 | value << 24; | ||
790 | value64 = (value64 & 0xffffffff) | value64 << 32; | ||
791 | prefix = 8 - ((unsigned long)start) % 8; | ||
792 | |||
793 | if (prefix) { | ||
794 | u8 *r = check_bytes8(start, value, prefix); | ||
795 | if (r) | ||
796 | return r; | ||
797 | start += prefix; | ||
798 | bytes -= prefix; | ||
799 | } | ||
800 | |||
801 | words = bytes / 8; | ||
802 | |||
803 | while (words) { | ||
804 | if (*(u64 *)start != value64) | ||
805 | return check_bytes8(start, value, 8); | ||
806 | start += 8; | ||
807 | words--; | ||
808 | } | ||
809 | |||
810 | return check_bytes8(start, value, bytes % 8); | ||
811 | } | ||
812 | EXPORT_SYMBOL(memchr_inv); | ||