[PATCH] bitmap: Fix optimization of bitmap_set/clear for big-endian machines

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Commit 2a98dc028f91 ("include/linux/bitmap.h: turn bitmap_set and
bitmap_clear into memset when possible", 2017-07-10) added an
optimization which effectively assumes that a contiguous set of
bits in a bitmap will be stored in a contiguous set of bytes of
the bitmap, in the case where the starting bit number and number of
bits are multiples of 8.  This is true for a little-endian
representation, but not for a big-endian representation, because we
number the bits of a long from right to left for both little-endian
and big-endian representations.

The optimization can still be done for big-endian platforms, but
only if the starting bit number and number of bits are multiples
of BITS_PER_LONG.  This adjusts the code to use 8 for little-endian
and BITS_PER_LONG for big-endian platforms.

Cc: stable@xxxxxxxxxxxxxxx # v4.13
Fixes: 2a98dc028f91 ("include/linux/bitmap.h: turn bitmap_set and bitmap_clear into memset when possible")
Signed-off-by: Paul Mackerras <paulus@xxxxxxxxxx>
---
This was found by inspection.

I'm pretty sure commit 2c6deb01525a is wrong as well on big-endian
machines.

 include/linux/bitmap.h | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h
index 700cf5f..44e2eb4 100644
--- a/include/linux/bitmap.h
+++ b/include/linux/bitmap.h
@@ -174,8 +174,10 @@ extern unsigned int bitmap_to_u32array(u32 *buf,
 				       unsigned int nbits);
 #ifdef __BIG_ENDIAN
 extern void bitmap_copy_le(unsigned long *dst, const unsigned long *src, unsigned int nbits);
+#define BITMAP_MIN_UNIT	BITS_PER_LONG	/* have to access as longs */
 #else
 #define bitmap_copy_le bitmap_copy
+#define BITMAP_MIN_UNIT	8		/* can access as bytes if desired */
 #endif
 extern unsigned int bitmap_ord_to_pos(const unsigned long *bitmap, unsigned int ord, unsigned int nbits);
 extern int bitmap_print_to_pagebuf(bool list, char *buf,
@@ -317,8 +319,10 @@ static __always_inline void bitmap_set(unsigned long *map, unsigned int start,
 {
 	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_MIN_UNIT-1)) &&
+		 IS_ALIGNED(start, BITMAP_MIN_UNIT) &&
+		 __builtin_constant_p(nbits & (BITMAP_MIN_UNIT-1)) &&
+		 IS_ALIGNED(nbits, BITMAP_MIN_UNIT))
 		memset((char *)map + start / 8, 0xff, nbits / 8);
 	else
 		__bitmap_set(map, start, nbits);
@@ -329,8 +333,10 @@ static __always_inline void bitmap_clear(unsigned long *map, unsigned int start,
 {
 	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_MIN_UNIT-1)) &&
+		 IS_ALIGNED(start, BITMAP_MIN_UNIT) &&
+		 __builtin_constant_p(nbits & (BITMAP_MIN_UNIT-1)) &&
+		 IS_ALIGNED(nbits, BITMAP_MIN_UNIT))
 		memset((char *)map + start / 8, 0, nbits / 8);
 	else
 		__bitmap_clear(map, start, nbits);
-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe linux-s390" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Kernel Development]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Info]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Linux Media]     [Device Mapper]

  Powered by Linux