Skip to content

Commit f2d282e

Browse files
committed
Merge tag 'bitmap-for-6.17' of https://github.com/norov/linux
Pull bitmap updates from Yury Norov: - find_random_bit() series (Yury) - GENMASK() consolidation (Vincent) - random cleanups (Shaopeng, Ben, Yury) * tag 'bitmap-for-6.17' of https://github.com/norov/linux: bitfield: Ensure the return values of helper functions are checked test_bits: add tests for __GENMASK() and __GENMASK_ULL() bits: unify the non-asm GENMASK*() bits: split the definition of the asm and non-asm GENMASK*() cpumask: Remove unnecessary cpumask_nth_andnot() watchdog: fix opencoded cpumask_next_wrap() in watchdog_next_cpu() clocksource: Improve randomness in clocksource_verify_choose_cpus() cpumask: introduce cpumask_random() bitmap: generalize node_random()
2 parents 6a68cec + e2b02d3 commit f2d282e

File tree

9 files changed

+72
-93
lines changed

9 files changed

+72
-93
lines changed

include/linux/bitfield.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,14 +189,14 @@ static __always_inline u64 field_mask(u64 field)
189189
}
190190
#define field_max(field) ((typeof(field))field_mask(field))
191191
#define ____MAKE_OP(type,base,to,from) \
192-
static __always_inline __##type type##_encode_bits(base v, base field) \
192+
static __always_inline __##type __must_check type##_encode_bits(base v, base field) \
193193
{ \
194194
if (__builtin_constant_p(v) && (v & ~field_mask(field))) \
195195
__field_overflow(); \
196196
return to((v & field_mask(field)) * field_multiplier(field)); \
197197
} \
198-
static __always_inline __##type type##_replace_bits(__##type old, \
199-
base val, base field) \
198+
static __always_inline __##type __must_check type##_replace_bits(__##type old, \
199+
base val, base field) \
200200
{ \
201201
return (old & ~to(field)) | type##_encode_bits(val, field); \
202202
} \
@@ -205,7 +205,7 @@ static __always_inline void type##p_replace_bits(__##type *p, \
205205
{ \
206206
*p = (*p & ~to(field)) | type##_encode_bits(val, field); \
207207
} \
208-
static __always_inline base type##_get_bits(__##type v, base field) \
208+
static __always_inline base __must_check type##_get_bits(__##type v, base field) \
209209
{ \
210210
return (from(v) & field)/field_multiplier(field); \
211211
}

include/linux/bits.h

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@
22
#ifndef __LINUX_BITS_H
33
#define __LINUX_BITS_H
44

5-
#include <linux/const.h>
65
#include <vdso/bits.h>
76
#include <uapi/linux/bits.h>
8-
#include <asm/bitsperlong.h>
97

108
#define BIT_MASK(nr) (UL(1) << ((nr) % BITS_PER_LONG))
119
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
@@ -50,10 +48,14 @@
5048
(type_max(t) << (l) & \
5149
type_max(t) >> (BITS_PER_TYPE(t) - 1 - (h)))))
5250

51+
#define GENMASK(h, l) GENMASK_TYPE(unsigned long, h, l)
52+
#define GENMASK_ULL(h, l) GENMASK_TYPE(unsigned long long, h, l)
53+
5354
#define GENMASK_U8(h, l) GENMASK_TYPE(u8, h, l)
5455
#define GENMASK_U16(h, l) GENMASK_TYPE(u16, h, l)
5556
#define GENMASK_U32(h, l) GENMASK_TYPE(u32, h, l)
5657
#define GENMASK_U64(h, l) GENMASK_TYPE(u64, h, l)
58+
#define GENMASK_U128(h, l) GENMASK_TYPE(u128, h, l)
5759

5860
/*
5961
* Fixed-type variants of BIT(), with additional checks like GENMASK_TYPE(). The
@@ -79,28 +81,9 @@
7981
* BUILD_BUG_ON_ZERO is not available in h files included from asm files,
8082
* disable the input check if that is the case.
8183
*/
82-
#define GENMASK_INPUT_CHECK(h, l) 0
84+
#define GENMASK(h, l) __GENMASK(h, l)
85+
#define GENMASK_ULL(h, l) __GENMASK_ULL(h, l)
8386

8487
#endif /* !defined(__ASSEMBLY__) */
8588

86-
#define GENMASK(h, l) \
87-
(GENMASK_INPUT_CHECK(h, l) + __GENMASK(h, l))
88-
#define GENMASK_ULL(h, l) \
89-
(GENMASK_INPUT_CHECK(h, l) + __GENMASK_ULL(h, l))
90-
91-
#if !defined(__ASSEMBLY__)
92-
/*
93-
* Missing asm support
94-
*
95-
* __GENMASK_U128() depends on _BIT128() which would not work
96-
* in the asm code, as it shifts an 'unsigned __int128' data
97-
* type instead of direct representation of 128 bit constants
98-
* such as long and unsigned long. The fundamental problem is
99-
* that a 128 bit constant will get silently truncated by the
100-
* gcc compiler.
101-
*/
102-
#define GENMASK_U128(h, l) \
103-
(GENMASK_INPUT_CHECK(h, l) + __GENMASK_U128(h, l))
104-
#endif
105-
10689
#endif /* __LINUX_BITS_H */

include/linux/cpumask.h

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,18 @@ unsigned int cpumask_next_wrap(int n, const struct cpumask *src)
354354
return find_next_bit_wrap(cpumask_bits(src), small_cpumask_bits, n + 1);
355355
}
356356

357+
/**
358+
* cpumask_random - get random cpu in *src.
359+
* @src: cpumask pointer
360+
*
361+
* Return: random set bit, or >= nr_cpu_ids if @src is empty.
362+
*/
363+
static __always_inline
364+
unsigned int cpumask_random(const struct cpumask *src)
365+
{
366+
return find_random_bit(cpumask_bits(src), nr_cpu_ids);
367+
}
368+
357369
/**
358370
* for_each_cpu - iterate over every cpu in a mask
359371
* @cpu: the (optionally unsigned) integer iterator
@@ -546,22 +558,6 @@ unsigned int cpumask_nth_and(unsigned int cpu, const struct cpumask *srcp1,
546558
small_cpumask_bits, cpumask_check(cpu));
547559
}
548560

549-
/**
550-
* cpumask_nth_andnot - get the Nth cpu set in 1st cpumask, and clear in 2nd.
551-
* @srcp1: the cpumask pointer
552-
* @srcp2: the cpumask pointer
553-
* @cpu: the Nth cpu to find, starting from 0
554-
*
555-
* Return: >= nr_cpu_ids if such cpu doesn't exist.
556-
*/
557-
static __always_inline
558-
unsigned int cpumask_nth_andnot(unsigned int cpu, const struct cpumask *srcp1,
559-
const struct cpumask *srcp2)
560-
{
561-
return find_nth_andnot_bit(cpumask_bits(srcp1), cpumask_bits(srcp2),
562-
small_cpumask_bits, cpumask_check(cpu));
563-
}
564-
565561
/**
566562
* cpumask_nth_and_andnot - get the Nth cpu set in 1st and 2nd cpumask, and clear in 3rd.
567563
* @srcp1: the cpumask pointer

include/linux/find.h

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ unsigned long _find_next_bit_le(const unsigned long *addr, unsigned
4444
long size, unsigned long offset);
4545
#endif
4646

47+
unsigned long find_random_bit(const unsigned long *addr, unsigned long size);
48+
4749
#ifndef find_next_bit
4850
/**
4951
* find_next_bit - find the next set bit in a memory region
@@ -267,33 +269,6 @@ unsigned long find_nth_and_bit(const unsigned long *addr1, const unsigned long *
267269
return __find_nth_and_bit(addr1, addr2, size, n);
268270
}
269271

270-
/**
271-
* find_nth_andnot_bit - find N'th set bit in 2 memory regions,
272-
* flipping bits in 2nd region
273-
* @addr1: The 1st address to start the search at
274-
* @addr2: The 2nd address to start the search at
275-
* @size: The maximum number of bits to search
276-
* @n: The number of set bit, which position is needed, counting from 0
277-
*
278-
* Returns the bit number of the N'th set bit.
279-
* If no such, returns @size.
280-
*/
281-
static __always_inline
282-
unsigned long find_nth_andnot_bit(const unsigned long *addr1, const unsigned long *addr2,
283-
unsigned long size, unsigned long n)
284-
{
285-
if (n >= size)
286-
return size;
287-
288-
if (small_const_nbits(size)) {
289-
unsigned long val = *addr1 & (~*addr2) & GENMASK(size - 1, 0);
290-
291-
return val ? fns(val, n) : size;
292-
}
293-
294-
return __find_nth_andnot_bit(addr1, addr2, size, n);
295-
}
296-
297272
/**
298273
* find_nth_and_andnot_bit - find N'th set bit in 2 memory regions,
299274
* excluding those set in 3rd region

include/linux/nodemask.h

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -492,21 +492,9 @@ static __always_inline int num_node_state(enum node_states state)
492492
static __always_inline int node_random(const nodemask_t *maskp)
493493
{
494494
#if defined(CONFIG_NUMA) && (MAX_NUMNODES > 1)
495-
int w, bit;
496-
497-
w = nodes_weight(*maskp);
498-
switch (w) {
499-
case 0:
500-
bit = NUMA_NO_NODE;
501-
break;
502-
case 1:
503-
bit = first_node(*maskp);
504-
break;
505-
default:
506-
bit = find_nth_bit(maskp->bits, MAX_NUMNODES, get_random_u32_below(w));
507-
break;
508-
}
509-
return bit;
495+
int node = find_random_bit(maskp->bits, MAX_NUMNODES);
496+
497+
return node < MAX_NUMNODES ? node : NUMA_NO_NODE;
510498
#else
511499
return 0;
512500
#endif

kernel/time/clocksource.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -340,10 +340,7 @@ static void clocksource_verify_choose_cpus(void)
340340
* CPUs that are currently online.
341341
*/
342342
for (i = 1; i < n; i++) {
343-
cpu = get_random_u32_below(nr_cpu_ids);
344-
cpu = cpumask_next(cpu - 1, cpu_online_mask);
345-
if (cpu >= nr_cpu_ids)
346-
cpu = cpumask_first(cpu_online_mask);
343+
cpu = cpumask_random(cpu_online_mask);
347344
if (!WARN_ON_ONCE(cpu >= nr_cpu_ids))
348345
cpumask_set_cpu(cpu, &cpus_chosen);
349346
}

kernel/watchdog_buddy.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,7 @@ static unsigned int watchdog_next_cpu(unsigned int cpu)
1212
{
1313
unsigned int next_cpu;
1414

15-
next_cpu = cpumask_next(cpu, &watchdog_cpus);
16-
if (next_cpu >= nr_cpu_ids)
17-
next_cpu = cpumask_first(&watchdog_cpus);
18-
15+
next_cpu = cpumask_next_wrap(cpu, &watchdog_cpus);
1916
if (next_cpu == cpu)
2017
return nr_cpu_ids;
2118

lib/find_bit.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <linux/math.h>
1919
#include <linux/minmax.h>
2020
#include <linux/swab.h>
21+
#include <linux/random.h>
2122

2223
/*
2324
* Common helper for find_bit() function family
@@ -291,3 +292,26 @@ EXPORT_SYMBOL(_find_next_bit_le);
291292
#endif
292293

293294
#endif /* __BIG_ENDIAN */
295+
296+
/**
297+
* find_random_bit - find a set bit at random position
298+
* @addr: The address to base the search on
299+
* @size: The bitmap size in bits
300+
*
301+
* Returns: a position of a random set bit; >= @size otherwise
302+
*/
303+
unsigned long find_random_bit(const unsigned long *addr, unsigned long size)
304+
{
305+
int w = bitmap_weight(addr, size);
306+
307+
switch (w) {
308+
case 0:
309+
return size;
310+
case 1:
311+
/* Performance trick for single-bit bitmaps */
312+
return find_first_bit(addr, size);
313+
default:
314+
return find_nth_bit(addr, size, get_random_u32_below(w));
315+
}
316+
}
317+
EXPORT_SYMBOL(find_random_bit);

lib/tests/test_bits.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,23 @@ static_assert(assert_type(u16, GENMASK_U16(15, 0)) == U16_MAX);
2626
static_assert(assert_type(u32, GENMASK_U32(31, 0)) == U32_MAX);
2727
static_assert(assert_type(u64, GENMASK_U64(63, 0)) == U64_MAX);
2828

29+
/* FIXME: add a test case written in asm for GENMASK() and GENMASK_ULL() */
30+
31+
static void __genmask_test(struct kunit *test)
32+
{
33+
KUNIT_EXPECT_EQ(test, 1ul, __GENMASK(0, 0));
34+
KUNIT_EXPECT_EQ(test, 3ul, __GENMASK(1, 0));
35+
KUNIT_EXPECT_EQ(test, 6ul, __GENMASK(2, 1));
36+
KUNIT_EXPECT_EQ(test, 0xFFFFFFFFul, __GENMASK(31, 0));
37+
}
38+
39+
static void __genmask_ull_test(struct kunit *test)
40+
{
41+
KUNIT_EXPECT_EQ(test, 1ull, __GENMASK_ULL(0, 0));
42+
KUNIT_EXPECT_EQ(test, 3ull, __GENMASK_ULL(1, 0));
43+
KUNIT_EXPECT_EQ(test, 0x000000ffffe00000ull, __GENMASK_ULL(39, 21));
44+
KUNIT_EXPECT_EQ(test, 0xffffffffffffffffull, __GENMASK_ULL(63, 0));
45+
}
2946

3047
static void genmask_test(struct kunit *test)
3148
{
@@ -123,6 +140,8 @@ static void genmask_input_check_test(struct kunit *test)
123140

124141

125142
static struct kunit_case bits_test_cases[] = {
143+
KUNIT_CASE(__genmask_test),
144+
KUNIT_CASE(__genmask_ull_test),
126145
KUNIT_CASE(genmask_test),
127146
KUNIT_CASE(genmask_ull_test),
128147
KUNIT_CASE(genmask_u128_test),

0 commit comments

Comments
 (0)