From: Greg Kroah-Hartman Date: Wed, 4 Apr 2018 08:11:20 +0000 (+0200) Subject: 4.16-stable patches X-Git-Tag: v3.18.103~21 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c6b12c62899de819d6de9fdfd8888501ef7656be;p=thirdparty%2Fkernel%2Fstable-queue.git 4.16-stable patches added patches: bitmap-fix-memset-optimization-on-big-endian-systems.patch --- diff --git a/queue-4.16/bitmap-fix-memset-optimization-on-big-endian-systems.patch b/queue-4.16/bitmap-fix-memset-optimization-on-big-endian-systems.patch new file mode 100644 index 00000000000..46fab95f668 --- /dev/null +++ b/queue-4.16/bitmap-fix-memset-optimization-on-big-endian-systems.patch @@ -0,0 +1,89 @@ +From 21035965f60b0502fc6537b232839389bb4ce664 Mon Sep 17 00:00:00 2001 +From: Omar Sandoval +Date: Mon, 2 Apr 2018 15:58:31 -0700 +Subject: bitmap: fix memset optimization on big-endian systems + +From: Omar Sandoval + +commit 21035965f60b0502fc6537b232839389bb4ce664 upstream. + +Commit 2a98dc028f91 ("include/linux/bitmap.h: turn bitmap_set and +bitmap_clear into memset when possible") introduced an optimization to +bitmap_{set,clear}() which uses memset() when the start and length are +constants aligned to a byte. + +This is wrong on big-endian systems; our bitmaps are arrays of unsigned +long, so bit n is not at byte n / 8 in memory. This was caught by the +Btrfs selftests, but the bitmap selftests also fail when run on a +big-endian machine. + +We can still use memset if the start and length are aligned to an +unsigned long, so do that on big-endian. The same problem applies to +the memcmp in bitmap_equal(), so fix it there, too. + +Fixes: 2a98dc028f91 ("include/linux/bitmap.h: turn bitmap_set and bitmap_clear into memset when possible") +Fixes: 2c6deb01525a ("bitmap: use memcmp optimisation in more situations") +Cc: stable@kernel.org +Reported-by: "Erhard F." +Cc: Matthew Wilcox +Cc: Rasmus Villemoes +Cc: Andrew Morton +Cc: Arnd Bergmann +Signed-off-by: Omar Sandoval +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/bitmap.h | 22 +++++++++++++++++----- + 1 file changed, 17 insertions(+), 5 deletions(-) + +--- a/include/linux/bitmap.h ++++ b/include/linux/bitmap.h +@@ -302,12 +302,20 @@ static inline void bitmap_complement(uns + __bitmap_complement(dst, src, nbits); + } + ++#ifdef __LITTLE_ENDIAN ++#define BITMAP_MEM_ALIGNMENT 8 ++#else ++#define BITMAP_MEM_ALIGNMENT (8 * sizeof(unsigned long)) ++#endif ++#define BITMAP_MEM_MASK (BITMAP_MEM_ALIGNMENT - 1) ++ + static inline int bitmap_equal(const unsigned long *src1, + const unsigned long *src2, unsigned int nbits) + { + if (small_const_nbits(nbits)) + return !((*src1 ^ *src2) & BITMAP_LAST_WORD_MASK(nbits)); +- if (__builtin_constant_p(nbits & 7) && IS_ALIGNED(nbits, 8)) ++ if (__builtin_constant_p(nbits & BITMAP_MEM_MASK) && ++ IS_ALIGNED(nbits, BITMAP_MEM_ALIGNMENT)) + return !memcmp(src1, src2, nbits / 8); + return __bitmap_equal(src1, src2, nbits); + } +@@ -358,8 +366,10 @@ static __always_inline void bitmap_set(u + { + if (__builtin_constant_p(nbits) && nbits == 1) + __set_bit(start, map); +- else if (__builtin_constant_p(start & 7) && IS_ALIGNED(start, 8) && +- __builtin_constant_p(nbits & 7) && IS_ALIGNED(nbits, 8)) ++ else if (__builtin_constant_p(start & BITMAP_MEM_MASK) && ++ IS_ALIGNED(start, BITMAP_MEM_ALIGNMENT) && ++ __builtin_constant_p(nbits & BITMAP_MEM_MASK) && ++ IS_ALIGNED(nbits, BITMAP_MEM_ALIGNMENT)) + memset((char *)map + start / 8, 0xff, nbits / 8); + else + __bitmap_set(map, start, nbits); +@@ -370,8 +380,10 @@ static __always_inline void bitmap_clear + { + if (__builtin_constant_p(nbits) && nbits == 1) + __clear_bit(start, map); +- else if (__builtin_constant_p(start & 7) && IS_ALIGNED(start, 8) && +- __builtin_constant_p(nbits & 7) && IS_ALIGNED(nbits, 8)) ++ else if (__builtin_constant_p(start & BITMAP_MEM_MASK) && ++ IS_ALIGNED(start, BITMAP_MEM_ALIGNMENT) && ++ __builtin_constant_p(nbits & BITMAP_MEM_MASK) && ++ IS_ALIGNED(nbits, BITMAP_MEM_ALIGNMENT)) + memset((char *)map + start / 8, 0, nbits / 8); + else + __bitmap_clear(map, start, nbits);