lib/bitmap: add bitmap_{read,write}()
[ Upstream commit 63c15822b8dd02a2423cfd92232245ace3f7a11b ] The two new functions allow reading/writing values of length up to BITS_PER_LONG bits at arbitrary position in the bitmap. The code was taken from "bitops: Introduce the for_each_set_clump macro" by Syed Nayyar Waris with a number of changes and simplifications: - instead of using roundup(), which adds an unnecessary dependency on <linux/math.h>, we calculate space as BITS_PER_LONG-offset; - indentation is reduced by not using else-clauses (suggested by checkpatch for bitmap_get_value()); - bitmap_get_value()/bitmap_set_value() are renamed to bitmap_read() and bitmap_write(); - some redundant computations are omitted. Cc: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Syed Nayyar Waris <syednwaris@gmail.com> Signed-off-by: William Breathitt Gray <william.gray@linaro.org> Link: https://lore.kernel.org/lkml/fe12eedf3666f4af5138de0e70b67a07c7f40338.1592224129.git.syednwaris@gmail.com/ Suggested-by: Yury Norov <yury.norov@gmail.com> Co-developed-by: Alexander Potapenko <glider@google.com> Signed-off-by: Alexander Potapenko <glider@google.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Acked-by: Yury Norov <yury.norov@gmail.com> Signed-off-by: Yury Norov <yury.norov@gmail.com> Signed-off-by: Alexander Lobakin <aleksander.lobakin@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net> Stable-dep-of: 77b0b98bb743 ("btrfs: subpage: fix the bitmap dump which can cause bitmap corruption") Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
32e93cae4d
commit
459b724c3c
|
@ -77,6 +77,10 @@ struct device;
|
|||
* 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
|
||||
* bitmap_read(map, start, nbits) Read an nbits-sized value from
|
||||
* map at start
|
||||
* bitmap_write(map, value, start, nbits) Write an nbits-sized value to
|
||||
* map at start
|
||||
*
|
||||
* Note, bitmap_zero() and bitmap_fill() operate over the region of
|
||||
* unsigned longs, that is, bits behind bitmap till the unsigned long
|
||||
|
@ -613,6 +617,79 @@ static inline void bitmap_set_value8(unsigned long *map, unsigned long value,
|
|||
map[index] |= value << offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* bitmap_read - read a value of n-bits from the memory region
|
||||
* @map: address to the bitmap memory region
|
||||
* @start: bit offset of the n-bit value
|
||||
* @nbits: size of value in bits, nonzero, up to BITS_PER_LONG
|
||||
*
|
||||
* Returns: value of @nbits bits located at the @start bit offset within the
|
||||
* @map memory region. For @nbits = 0 and @nbits > BITS_PER_LONG the return
|
||||
* value is undefined.
|
||||
*/
|
||||
static inline unsigned long bitmap_read(const unsigned long *map,
|
||||
unsigned long start,
|
||||
unsigned long nbits)
|
||||
{
|
||||
size_t index = BIT_WORD(start);
|
||||
unsigned long offset = start % BITS_PER_LONG;
|
||||
unsigned long space = BITS_PER_LONG - offset;
|
||||
unsigned long value_low, value_high;
|
||||
|
||||
if (unlikely(!nbits || nbits > BITS_PER_LONG))
|
||||
return 0;
|
||||
|
||||
if (space >= nbits)
|
||||
return (map[index] >> offset) & BITMAP_LAST_WORD_MASK(nbits);
|
||||
|
||||
value_low = map[index] & BITMAP_FIRST_WORD_MASK(start);
|
||||
value_high = map[index + 1] & BITMAP_LAST_WORD_MASK(start + nbits);
|
||||
return (value_low >> offset) | (value_high << space);
|
||||
}
|
||||
|
||||
/**
|
||||
* bitmap_write - write n-bit value within a memory region
|
||||
* @map: address to the bitmap memory region
|
||||
* @value: value to write, clamped to nbits
|
||||
* @start: bit offset of the n-bit value
|
||||
* @nbits: size of value in bits, nonzero, up to BITS_PER_LONG.
|
||||
*
|
||||
* bitmap_write() behaves as-if implemented as @nbits calls of __assign_bit(),
|
||||
* i.e. bits beyond @nbits are ignored:
|
||||
*
|
||||
* for (bit = 0; bit < nbits; bit++)
|
||||
* __assign_bit(start + bit, bitmap, val & BIT(bit));
|
||||
*
|
||||
* For @nbits == 0 and @nbits > BITS_PER_LONG no writes are performed.
|
||||
*/
|
||||
static inline void bitmap_write(unsigned long *map, unsigned long value,
|
||||
unsigned long start, unsigned long nbits)
|
||||
{
|
||||
size_t index;
|
||||
unsigned long offset;
|
||||
unsigned long space;
|
||||
unsigned long mask;
|
||||
bool fit;
|
||||
|
||||
if (unlikely(!nbits || nbits > BITS_PER_LONG))
|
||||
return;
|
||||
|
||||
mask = BITMAP_LAST_WORD_MASK(nbits);
|
||||
value &= mask;
|
||||
offset = start % BITS_PER_LONG;
|
||||
space = BITS_PER_LONG - offset;
|
||||
fit = space >= nbits;
|
||||
index = BIT_WORD(start);
|
||||
|
||||
map[index] &= (fit ? (~(mask << offset)) : ~BITMAP_FIRST_WORD_MASK(start));
|
||||
map[index] |= value << offset;
|
||||
if (fit)
|
||||
return;
|
||||
|
||||
map[index + 1] &= BITMAP_FIRST_WORD_MASK(start + nbits);
|
||||
map[index + 1] |= (value >> space);
|
||||
}
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#endif /* __LINUX_BITMAP_H */
|
||||
|
|
Loading…
Reference in New Issue