Skip to content

Commit cb0f800

Browse files
kkdwvdAlexei Starovoitov
authored andcommitted
bitops: Add non-atomic bitops for pointers
cpumap needs to set, clear, and test the lowest bit in skb pointer in various places. To make these checks less noisy, add pointer friendly bitop macros that also do some typechecking to sanitize the argument. These wrap the non-atomic bitops __set_bit, __clear_bit, and test_bit but for pointer arguments. Pointer's address has to be passed in and it is treated as an unsigned long *, since width and representation of pointer and unsigned long match on targets Linux supports. They are prefixed with double underscore to indicate lack of atomicity. Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com> Link: https://lore.kernel.org/bpf/20210702111825.491065-3-memxor@gmail.com
1 parent fe21cb9 commit cb0f800

File tree

2 files changed

+59
-0
lines changed

2 files changed

+59
-0
lines changed

include/linux/bitops.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include <asm/types.h>
66
#include <linux/bits.h>
7+
#include <linux/typecheck.h>
78

89
#include <uapi/linux/kernel.h>
910

@@ -253,6 +254,55 @@ static __always_inline void __assign_bit(long nr, volatile unsigned long *addr,
253254
__clear_bit(nr, addr);
254255
}
255256

257+
/**
258+
* __ptr_set_bit - Set bit in a pointer's value
259+
* @nr: the bit to set
260+
* @addr: the address of the pointer variable
261+
*
262+
* Example:
263+
* void *p = foo();
264+
* __ptr_set_bit(bit, &p);
265+
*/
266+
#define __ptr_set_bit(nr, addr) \
267+
({ \
268+
typecheck_pointer(*(addr)); \
269+
__set_bit(nr, (unsigned long *)(addr)); \
270+
})
271+
272+
/**
273+
* __ptr_clear_bit - Clear bit in a pointer's value
274+
* @nr: the bit to clear
275+
* @addr: the address of the pointer variable
276+
*
277+
* Example:
278+
* void *p = foo();
279+
* __ptr_clear_bit(bit, &p);
280+
*/
281+
#define __ptr_clear_bit(nr, addr) \
282+
({ \
283+
typecheck_pointer(*(addr)); \
284+
__clear_bit(nr, (unsigned long *)(addr)); \
285+
})
286+
287+
/**
288+
* __ptr_test_bit - Test bit in a pointer's value
289+
* @nr: the bit to test
290+
* @addr: the address of the pointer variable
291+
*
292+
* Example:
293+
* void *p = foo();
294+
* if (__ptr_test_bit(bit, &p)) {
295+
* ...
296+
* } else {
297+
* ...
298+
* }
299+
*/
300+
#define __ptr_test_bit(nr, addr) \
301+
({ \
302+
typecheck_pointer(*(addr)); \
303+
test_bit(nr, (unsigned long *)(addr)); \
304+
})
305+
256306
#ifdef __KERNEL__
257307

258308
#ifndef set_mask_bits

include/linux/typecheck.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,13 @@
2222
(void)__tmp; \
2323
})
2424

25+
/*
26+
* Check at compile time that something is a pointer type.
27+
*/
28+
#define typecheck_pointer(x) \
29+
({ typeof(x) __dummy; \
30+
(void)sizeof(*__dummy); \
31+
1; \
32+
})
33+
2534
#endif /* TYPECHECK_H_INCLUDED */

0 commit comments

Comments
 (0)