Skip to content

Commit 0a97953

Browse files
committed
lib: add bitmap_{from,to}_arr64
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 <[email protected]> CC: Andy Shevchenko <[email protected]> CC: Christian Borntraeger <[email protected]> CC: Claudio Imbrenda <[email protected]> CC: David Hildenbrand <[email protected]> CC: Heiko Carstens <[email protected]> CC: Janosch Frank <[email protected]> CC: Rasmus Villemoes <[email protected]> CC: Sven Schnelle <[email protected]> CC: Vasily Gorbik <[email protected]> Signed-off-by: Yury Norov <[email protected]>
1 parent e041e0a commit 0a97953

File tree

2 files changed

+73
-4
lines changed

2 files changed

+73
-4
lines changed

include/linux/bitmap.h

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ struct device;
7272
* bitmap_allocate_region(bitmap, pos, order) Allocate specified bit region
7373
* bitmap_from_arr32(dst, buf, nbits) Copy nbits from u32[] buf to dst
7474
* bitmap_to_arr32(buf, src, nbits) Copy nbits from buf to u32[] dst
75+
* bitmap_to_arr64(buf, src, nbits) Copy nbits from buf to u64[] dst
76+
* bitmap_to_arr64(buf, src, nbits) Copy nbits from buf to u64[] dst
7577
* bitmap_get_value8(map, start) Get 8bit value from map at start
7678
* bitmap_set_value8(map, value, start) Set 8bit value to map at start
7779
*
@@ -285,6 +287,22 @@ void bitmap_to_arr32(u32 *buf, const unsigned long *bitmap,
285287
(const unsigned long *) (bitmap), (nbits))
286288
#endif
287289

290+
/*
291+
* On 64-bit systems bitmaps are represented as u64 arrays internally. On LE32
292+
* machines the order of hi and lo parts of numbers match the bitmap structure.
293+
* In both cases conversion is not needed when copying data from/to arrays of
294+
* u64.
295+
*/
296+
#if (BITS_PER_LONG == 32) && defined(__BIG_ENDIAN)
297+
void bitmap_from_arr64(unsigned long *bitmap, const u64 *buf, unsigned int nbits);
298+
void bitmap_to_arr64(u64 *buf, const unsigned long *bitmap, unsigned int nbits);
299+
#else
300+
#define bitmap_from_arr64(bitmap, buf, nbits) \
301+
bitmap_copy_clear_tail((unsigned long *)(bitmap), (const unsigned long *)(buf), (nbits))
302+
#define bitmap_to_arr64(buf, bitmap, nbits) \
303+
bitmap_copy_clear_tail((unsigned long *)(buf), (const unsigned long *)(bitmap), (nbits))
304+
#endif
305+
288306
static inline int bitmap_and(unsigned long *dst, const unsigned long *src1,
289307
const unsigned long *src2, unsigned int nbits)
290308
{
@@ -518,10 +536,7 @@ static inline void bitmap_next_set_region(unsigned long *bitmap,
518536
*/
519537
static inline void bitmap_from_u64(unsigned long *dst, u64 mask)
520538
{
521-
dst[0] = mask & ULONG_MAX;
522-
523-
if (sizeof(mask) > sizeof(unsigned long))
524-
dst[1] = mask >> 32;
539+
bitmap_from_arr64(dst, &mask, 64);
525540
}
526541

527542
/**

lib/bitmap.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1512,5 +1512,59 @@ void bitmap_to_arr32(u32 *buf, const unsigned long *bitmap, unsigned int nbits)
15121512
buf[halfwords - 1] &= (u32) (UINT_MAX >> ((-nbits) & 31));
15131513
}
15141514
EXPORT_SYMBOL(bitmap_to_arr32);
1515+
#endif
1516+
1517+
#if (BITS_PER_LONG == 32) && defined(__BIG_ENDIAN)
1518+
/**
1519+
* bitmap_from_arr64 - copy the contents of u64 array of bits to bitmap
1520+
* @bitmap: array of unsigned longs, the destination bitmap
1521+
* @buf: array of u64 (in host byte order), the source bitmap
1522+
* @nbits: number of bits in @bitmap
1523+
*/
1524+
void bitmap_from_arr64(unsigned long *bitmap, const u64 *buf, unsigned int nbits)
1525+
{
1526+
int n;
1527+
1528+
for (n = nbits; n > 0; n -= 64) {
1529+
u64 val = *buf++;
1530+
1531+
*bitmap++ = val;
1532+
if (n > 32)
1533+
*bitmap++ = val >> 32;
1534+
}
1535+
1536+
/*
1537+
* Clear tail bits in the last word beyond nbits.
1538+
*
1539+
* Negative index is OK because here we point to the word next
1540+
* to the last word of the bitmap, except for nbits == 0, which
1541+
* is tested implicitly.
1542+
*/
1543+
if (nbits % BITS_PER_LONG)
1544+
bitmap[-1] &= BITMAP_LAST_WORD_MASK(nbits);
1545+
}
1546+
EXPORT_SYMBOL(bitmap_from_arr64);
1547+
1548+
/**
1549+
* bitmap_to_arr64 - copy the contents of bitmap to a u64 array of bits
1550+
* @buf: array of u64 (in host byte order), the dest bitmap
1551+
* @bitmap: array of unsigned longs, the source bitmap
1552+
* @nbits: number of bits in @bitmap
1553+
*/
1554+
void bitmap_to_arr64(u64 *buf, const unsigned long *bitmap, unsigned int nbits)
1555+
{
1556+
const unsigned long *end = bitmap + BITS_TO_LONGS(nbits);
15151557

1558+
while (bitmap < end) {
1559+
*buf = *bitmap++;
1560+
if (bitmap < end)
1561+
*buf |= (u64)(*bitmap++) << 32;
1562+
buf++;
1563+
}
1564+
1565+
/* Clear tail bits in the last element of array beyond nbits. */
1566+
if (nbits % 64)
1567+
buf[-1] &= GENMASK_ULL(nbits % 64, 0);
1568+
}
1569+
EXPORT_SYMBOL(bitmap_to_arr64);
15161570
#endif

0 commit comments

Comments
 (0)