kcsan: Update API documentation in kcsan-checks.h

Update the API documentation for ASSERT_EXCLUSIVE_* macros and make them
generate readable documentation for the code examples.

All @variable short summaries were missing ':', which was updated for
the whole file.

Tested with "make htmldocs".

Signed-off-by: Marco Elver <elver@google.com>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
This commit is contained in:
Marco Elver 2020-03-05 15:21:09 +01:00 committed by Paul E. McKenney
parent e7325b774c
commit 1443b8c9e7

View File

@ -26,9 +26,9 @@
/** /**
* __kcsan_check_access - check generic access for races * __kcsan_check_access - check generic access for races
* *
* @ptr address of access * @ptr: address of access
* @size size of access * @size: size of access
* @type access type modifier * @type: access type modifier
*/ */
void __kcsan_check_access(const volatile void *ptr, size_t size, int type); void __kcsan_check_access(const volatile void *ptr, size_t size, int type);
@ -64,7 +64,7 @@ void kcsan_flat_atomic_end(void);
* Force treating the next n memory accesses for the current context as atomic * Force treating the next n memory accesses for the current context as atomic
* operations. * operations.
* *
* @n number of following memory accesses to treat as atomic. * @n: number of following memory accesses to treat as atomic.
*/ */
void kcsan_atomic_next(int n); void kcsan_atomic_next(int n);
@ -74,7 +74,7 @@ void kcsan_atomic_next(int n);
* Set the access mask for all accesses for the current context if non-zero. * Set the access mask for all accesses for the current context if non-zero.
* Only value changes to bits set in the mask will be reported. * Only value changes to bits set in the mask will be reported.
* *
* @mask bitmask * @mask: bitmask
*/ */
void kcsan_set_access_mask(unsigned long mask); void kcsan_set_access_mask(unsigned long mask);
@ -106,16 +106,16 @@ static inline void kcsan_check_access(const volatile void *ptr, size_t size,
/** /**
* __kcsan_check_read - check regular read access for races * __kcsan_check_read - check regular read access for races
* *
* @ptr address of access * @ptr: address of access
* @size size of access * @size: size of access
*/ */
#define __kcsan_check_read(ptr, size) __kcsan_check_access(ptr, size, 0) #define __kcsan_check_read(ptr, size) __kcsan_check_access(ptr, size, 0)
/** /**
* __kcsan_check_write - check regular write access for races * __kcsan_check_write - check regular write access for races
* *
* @ptr address of access * @ptr: address of access
* @size size of access * @size: size of access
*/ */
#define __kcsan_check_write(ptr, size) \ #define __kcsan_check_write(ptr, size) \
__kcsan_check_access(ptr, size, KCSAN_ACCESS_WRITE) __kcsan_check_access(ptr, size, KCSAN_ACCESS_WRITE)
@ -123,16 +123,16 @@ static inline void kcsan_check_access(const volatile void *ptr, size_t size,
/** /**
* kcsan_check_read - check regular read access for races * kcsan_check_read - check regular read access for races
* *
* @ptr address of access * @ptr: address of access
* @size size of access * @size: size of access
*/ */
#define kcsan_check_read(ptr, size) kcsan_check_access(ptr, size, 0) #define kcsan_check_read(ptr, size) kcsan_check_access(ptr, size, 0)
/** /**
* kcsan_check_write - check regular write access for races * kcsan_check_write - check regular write access for races
* *
* @ptr address of access * @ptr: address of access
* @size size of access * @size: size of access
*/ */
#define kcsan_check_write(ptr, size) \ #define kcsan_check_write(ptr, size) \
kcsan_check_access(ptr, size, KCSAN_ACCESS_WRITE) kcsan_check_access(ptr, size, KCSAN_ACCESS_WRITE)
@ -158,14 +158,26 @@ static inline void kcsan_check_access(const volatile void *ptr, size_t size,
* allowed. This assertion can be used to specify properties of concurrent code, * allowed. This assertion can be used to specify properties of concurrent code,
* where violation cannot be detected as a normal data race. * where violation cannot be detected as a normal data race.
* *
* For example, if a per-CPU variable is only meant to be written by a single * For example, if we only have a single writer, but multiple concurrent
* CPU, but may be read from other CPUs; in this case, reads and writes must be * readers, to avoid data races, all these accesses must be marked; even
* marked properly, however, if an off-CPU WRITE_ONCE() races with the owning * concurrent marked writes racing with the single writer are bugs.
* CPU's WRITE_ONCE(), would not constitute a data race but could be a harmful * Unfortunately, due to being marked, they are no longer data races. For cases
* race condition. Using this macro allows specifying this property in the code * like these, we can use the macro as follows:
* and catch such bugs.
* *
* @var variable to assert on * .. code-block:: c
*
* void writer(void) {
* spin_lock(&update_foo_lock);
* ASSERT_EXCLUSIVE_WRITER(shared_foo);
* WRITE_ONCE(shared_foo, ...);
* spin_unlock(&update_foo_lock);
* }
* void reader(void) {
* // update_foo_lock does not need to be held!
* ... = READ_ONCE(shared_foo);
* }
*
* @var: variable to assert on
*/ */
#define ASSERT_EXCLUSIVE_WRITER(var) \ #define ASSERT_EXCLUSIVE_WRITER(var) \
__kcsan_check_access(&(var), sizeof(var), KCSAN_ACCESS_ASSERT) __kcsan_check_access(&(var), sizeof(var), KCSAN_ACCESS_ASSERT)
@ -177,16 +189,22 @@ static inline void kcsan_check_access(const volatile void *ptr, size_t size,
* writers). This assertion can be used to specify properties of concurrent * writers). This assertion can be used to specify properties of concurrent
* code, where violation cannot be detected as a normal data race. * code, where violation cannot be detected as a normal data race.
* *
* For example, in a reference-counting algorithm where exclusive access is * For example, where exclusive access is expected after determining no other
* expected after the refcount reaches 0. We can check that this property * users of an object are left, but the object is not actually freed. We can
* actually holds as follows: * check that this property actually holds as follows:
*
* .. code-block:: c
* *
* if (refcount_dec_and_test(&obj->refcnt)) { * if (refcount_dec_and_test(&obj->refcnt)) {
* ASSERT_EXCLUSIVE_ACCESS(*obj); * ASSERT_EXCLUSIVE_ACCESS(*obj);
* safely_dispose_of(obj); * do_some_cleanup(obj);
* release_for_reuse(obj);
* } * }
* *
* @var variable to assert on * Note: For cases where the object is freed, `KASAN <kasan.html>`_ is a better
* fit to detect use-after-free bugs.
*
* @var: variable to assert on
*/ */
#define ASSERT_EXCLUSIVE_ACCESS(var) \ #define ASSERT_EXCLUSIVE_ACCESS(var) \
__kcsan_check_access(&(var), sizeof(var), KCSAN_ACCESS_WRITE | KCSAN_ACCESS_ASSERT) __kcsan_check_access(&(var), sizeof(var), KCSAN_ACCESS_WRITE | KCSAN_ACCESS_ASSERT)
@ -200,7 +218,7 @@ static inline void kcsan_check_access(const volatile void *ptr, size_t size,
* concurrent readers are permitted. This assertion captures more detailed * concurrent readers are permitted. This assertion captures more detailed
* bit-level properties, compared to the other (word granularity) assertions. * bit-level properties, compared to the other (word granularity) assertions.
* Only the bits set in @mask are checked for concurrent modifications, while * Only the bits set in @mask are checked for concurrent modifications, while
* ignoring the remaining bits, i.e. concurrent writes (or reads) to ~@mask bits * ignoring the remaining bits, i.e. concurrent writes (or reads) to ~mask bits
* are ignored. * are ignored.
* *
* Use this for variables, where some bits must not be modified concurrently, * Use this for variables, where some bits must not be modified concurrently,
@ -210,17 +228,21 @@ static inline void kcsan_check_access(const volatile void *ptr, size_t size,
* but other bits may still be modified concurrently. A reader may wish to * but other bits may still be modified concurrently. A reader may wish to
* assert that this is true as follows: * assert that this is true as follows:
* *
* .. code-block:: c
*
* ASSERT_EXCLUSIVE_BITS(flags, READ_ONLY_MASK); * ASSERT_EXCLUSIVE_BITS(flags, READ_ONLY_MASK);
* foo = (READ_ONCE(flags) & READ_ONLY_MASK) >> READ_ONLY_SHIFT; * foo = (READ_ONCE(flags) & READ_ONLY_MASK) >> READ_ONLY_SHIFT;
* *
* Note: The access that immediately follows ASSERT_EXCLUSIVE_BITS() is * Note: The access that immediately follows ASSERT_EXCLUSIVE_BITS() is assumed
* assumed to access the masked bits only, and KCSAN optimistically assumes it * to access the masked bits only, and KCSAN optimistically assumes it is
* is therefore safe, even in the presence of data races, and marking it with * therefore safe, even in the presence of data races, and marking it with
* READ_ONCE() is optional from KCSAN's point-of-view. We caution, however, * READ_ONCE() is optional from KCSAN's point-of-view. We caution, however, that
* that it may still be advisable to do so, since we cannot reason about all * it may still be advisable to do so, since we cannot reason about all compiler
* compiler optimizations when it comes to bit manipulations (on the reader * optimizations when it comes to bit manipulations (on the reader and writer
* and writer side). If you are sure nothing can go wrong, we can write the * side). If you are sure nothing can go wrong, we can write the above simply
* above simply as: * as:
*
* .. code-block:: c
* *
* ASSERT_EXCLUSIVE_BITS(flags, READ_ONLY_MASK); * ASSERT_EXCLUSIVE_BITS(flags, READ_ONLY_MASK);
* foo = (flags & READ_ONLY_MASK) >> READ_ONLY_SHIFT; * foo = (flags & READ_ONLY_MASK) >> READ_ONLY_SHIFT;
@ -230,15 +252,17 @@ static inline void kcsan_check_access(const volatile void *ptr, size_t size,
* be modified concurrently. Writers, where other bits may change concurrently, * be modified concurrently. Writers, where other bits may change concurrently,
* could use the assertion as follows: * could use the assertion as follows:
* *
* .. code-block:: c
*
* spin_lock(&foo_lock); * spin_lock(&foo_lock);
* ASSERT_EXCLUSIVE_BITS(flags, FOO_MASK); * ASSERT_EXCLUSIVE_BITS(flags, FOO_MASK);
* old_flags = READ_ONCE(flags); * old_flags = flags;
* new_flags = (old_flags & ~FOO_MASK) | (new_foo << FOO_SHIFT); * new_flags = (old_flags & ~FOO_MASK) | (new_foo << FOO_SHIFT);
* if (cmpxchg(&flags, old_flags, new_flags) != old_flags) { ... } * if (cmpxchg(&flags, old_flags, new_flags) != old_flags) { ... }
* spin_unlock(&foo_lock); * spin_unlock(&foo_lock);
* *
* @var variable to assert on * @var: variable to assert on
* @mask only check for modifications to bits set in @mask * @mask: only check for modifications to bits set in @mask
*/ */
#define ASSERT_EXCLUSIVE_BITS(var, mask) \ #define ASSERT_EXCLUSIVE_BITS(var, mask) \
do { \ do { \