lib: add bitmap_{from,to}_arr64
authorYury Norov <yury.norov@gmail.com>
Thu, 28 Apr 2022 20:51:13 +0000 (13:51 -0700)
committerYury Norov <yury.norov@gmail.com>
Fri, 3 Jun 2022 13:52:58 +0000 (06:52 -0700)
Manipulating 64-bit arrays with bitmap functions is potentially dangerous
because on 32-bit BE machines the order of halfwords doesn't match.
Another issue is that compiler may throw a warning about out-of-boundary
access.

This patch adds bitmap_{from,to}_arr64 functions in addition to existing
bitmap_{from,to}_arr32.

CC: Alexander Gordeev <agordeev@linux.ibm.com>
CC: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
CC: Christian Borntraeger <borntraeger@linux.ibm.com>
CC: Claudio Imbrenda <imbrenda@linux.ibm.com>
CC: David Hildenbrand <david@redhat.com>
CC: Heiko Carstens <hca@linux.ibm.com>
CC: Janosch Frank <frankja@linux.ibm.com>
CC: Rasmus Villemoes <linux@rasmusvillemoes.dk>
CC: Sven Schnelle <svens@linux.ibm.com>
CC: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: Yury Norov <yury.norov@gmail.com>
include/linux/bitmap.h
lib/bitmap.c

index afcf7b8dddd196d2b92db8534354951eda16562f..71147b7d721bee6aeadead46084ba253116175b5 100644 (file)
@@ -72,6 +72,8 @@ struct device;
  *  bitmap_allocate_region(bitmap, pos, order)  Allocate specified bit region
  *  bitmap_from_arr32(dst, buf, nbits)          Copy nbits from u32[] buf to dst
  *  bitmap_to_arr32(buf, src, nbits)            Copy nbits from buf to u32[] dst
+ *  bitmap_to_arr64(buf, src, nbits)            Copy nbits from buf to u64[] dst
+ *  bitmap_to_arr64(buf, src, nbits)            Copy nbits from buf to u64[] dst
  *  bitmap_get_value8(map, start)               Get 8bit value from map at start
  *  bitmap_set_value8(map, value, start)        Set 8bit value to map at start
  *
@@ -285,6 +287,22 @@ void bitmap_to_arr32(u32 *buf, const unsigned long *bitmap,
                        (const unsigned long *) (bitmap), (nbits))
 #endif
 
+/*
+ * On 64-bit systems bitmaps are represented as u64 arrays internally. On LE32
+ * machines the order of hi and lo parts of numbers match the bitmap structure.
+ * In both cases conversion is not needed when copying data from/to arrays of
+ * u64.
+ */
+#if (BITS_PER_LONG == 32) && defined(__BIG_ENDIAN)
+void bitmap_from_arr64(unsigned long *bitmap, const u64 *buf, unsigned int nbits);
+void bitmap_to_arr64(u64 *buf, const unsigned long *bitmap, unsigned int nbits);
+#else
+#define bitmap_from_arr64(bitmap, buf, nbits)                  \
+       bitmap_copy_clear_tail((unsigned long *)(bitmap), (const unsigned long *)(buf), (nbits))
+#define bitmap_to_arr64(buf, bitmap, nbits)                    \
+       bitmap_copy_clear_tail((unsigned long *)(buf), (const unsigned long *)(bitmap), (nbits))
+#endif
+
 static inline int bitmap_and(unsigned long *dst, const unsigned long *src1,
                        const unsigned long *src2, unsigned int nbits)
 {
@@ -518,10 +536,7 @@ static inline void bitmap_next_set_region(unsigned long *bitmap,
  */
 static inline void bitmap_from_u64(unsigned long *dst, u64 mask)
 {
-       dst[0] = mask & ULONG_MAX;
-
-       if (sizeof(mask) > sizeof(unsigned long))
-               dst[1] = mask >> 32;
+       bitmap_from_arr64(dst, &mask, 64);
 }
 
 /**
index 8ebe508580ea766efc1ea9eca798286fbd56bc36..4061a5dd2bc67e8799262a1e7eb2b5a24cb34214 100644 (file)
@@ -1512,5 +1512,59 @@ void bitmap_to_arr32(u32 *buf, const unsigned long *bitmap, unsigned int nbits)
                buf[halfwords - 1] &= (u32) (UINT_MAX >> ((-nbits) & 31));
 }
 EXPORT_SYMBOL(bitmap_to_arr32);
+#endif
+
+#if (BITS_PER_LONG == 32) && defined(__BIG_ENDIAN)
+/**
+ * bitmap_from_arr64 - copy the contents of u64 array of bits to bitmap
+ *     @bitmap: array of unsigned longs, the destination bitmap
+ *     @buf: array of u64 (in host byte order), the source bitmap
+ *     @nbits: number of bits in @bitmap
+ */
+void bitmap_from_arr64(unsigned long *bitmap, const u64 *buf, unsigned int nbits)
+{
+       int n;
+
+       for (n = nbits; n > 0; n -= 64) {
+               u64 val = *buf++;
+
+               *bitmap++ = val;
+               if (n > 32)
+                       *bitmap++ = val >> 32;
+       }
+
+       /*
+        * Clear tail bits in the last word beyond nbits.
+        *
+        * Negative index is OK because here we point to the word next
+        * to the last word of the bitmap, except for nbits == 0, which
+        * is tested implicitly.
+        */
+       if (nbits % BITS_PER_LONG)
+               bitmap[-1] &= BITMAP_LAST_WORD_MASK(nbits);
+}
+EXPORT_SYMBOL(bitmap_from_arr64);
+
+/**
+ * bitmap_to_arr64 - copy the contents of bitmap to a u64 array of bits
+ *     @buf: array of u64 (in host byte order), the dest bitmap
+ *     @bitmap: array of unsigned longs, the source bitmap
+ *     @nbits: number of bits in @bitmap
+ */
+void bitmap_to_arr64(u64 *buf, const unsigned long *bitmap, unsigned int nbits)
+{
+       const unsigned long *end = bitmap + BITS_TO_LONGS(nbits);
 
+       while (bitmap < end) {
+               *buf = *bitmap++;
+               if (bitmap < end)
+                       *buf |= (u64)(*bitmap++) << 32;
+               buf++;
+       }
+
+       /* Clear tail bits in the last element of array beyond nbits. */
+       if (nbits % 64)
+               buf[-1] &= GENMASK_ULL(nbits % 64, 0);
+}
+EXPORT_SYMBOL(bitmap_to_arr64);
 #endif