Skip to content
/ linux Public
forked from torvalds/linux

Commit bd9e35c

Browse files
melvergregkh
authored andcommitted
kcsan, seqlock: Support seqcount_latch_t
[ Upstream commit 5c1806c ] While fuzzing an arm64 kernel, Alexander Potapenko reported: | BUG: KCSAN: data-race in ktime_get_mono_fast_ns / timekeeping_update | | write to 0xffffffc082e74248 of 56 bytes by interrupt on cpu 0: | update_fast_timekeeper kernel/time/timekeeping.c:430 [inline] | timekeeping_update+0x1d8/0x2d8 kernel/time/timekeeping.c:768 | timekeeping_advance+0x9e8/0xb78 kernel/time/timekeeping.c:2344 | update_wall_time+0x18/0x38 kernel/time/timekeeping.c:2360 | [...] | | read to 0xffffffc082e74258 of 8 bytes by task 5260 on cpu 1: | __ktime_get_fast_ns kernel/time/timekeeping.c:372 [inline] | ktime_get_mono_fast_ns+0x88/0x174 kernel/time/timekeeping.c:489 | init_srcu_struct_fields+0x40c/0x530 kernel/rcu/srcutree.c:263 | init_srcu_struct+0x14/0x20 kernel/rcu/srcutree.c:311 | [...] | | value changed: 0x000002f875d33266 -> 0x000002f877416866 | | Reported by Kernel Concurrency Sanitizer on: | CPU: 1 UID: 0 PID: 5260 Comm: syz.2.7483 Not tainted 6.12.0-rc3-dirty torvalds#78 This is a false positive data race between a seqcount latch writer and a reader accessing stale data. Since its introduction, KCSAN has never understood the seqcount_latch interface (due to being unannotated). Unlike the regular seqlock interface, the seqcount_latch interface for latch writers never has had a well-defined critical section, making it difficult to teach tooling where the critical section starts and ends. Introduce an instrumentable (non-raw) seqcount_latch interface, with which we can clearly denote writer critical sections. This both helps readability and tooling like KCSAN to understand when the writer is done updating all latch copies. Fixes: 88ecd15 ("seqlock, kcsan: Add annotations for KCSAN") Reported-by: Alexander Potapenko <[email protected]> Co-developed-by: "Peter Zijlstra (Intel)" <[email protected]> Signed-off-by: "Peter Zijlstra (Intel)" <[email protected]> Signed-off-by: Marco Elver <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Sasha Levin <[email protected]>
1 parent e15fd15 commit bd9e35c

File tree

2 files changed

+72
-16
lines changed

2 files changed

+72
-16
lines changed

Documentation/locking/seqlock.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ Use seqcount_latch_t when the write side sections cannot be protected
153153
from interruption by readers. This is typically the case when the read
154154
side can be invoked from NMI handlers.
155155

156-
Check `raw_write_seqcount_latch()` for more information.
156+
Check `write_seqcount_latch()` for more information.
157157

158158

159159
.. _seqlock_t:

include/linux/seqlock.h

+71-15
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,23 @@ static __always_inline unsigned raw_read_seqcount_latch(const seqcount_latch_t *
636636
return READ_ONCE(s->seqcount.sequence);
637637
}
638638

639+
/**
640+
* read_seqcount_latch() - pick even/odd latch data copy
641+
* @s: Pointer to seqcount_latch_t
642+
*
643+
* See write_seqcount_latch() for details and a full reader/writer usage
644+
* example.
645+
*
646+
* Return: sequence counter raw value. Use the lowest bit as an index for
647+
* picking which data copy to read. The full counter must then be checked
648+
* with read_seqcount_latch_retry().
649+
*/
650+
static __always_inline unsigned read_seqcount_latch(const seqcount_latch_t *s)
651+
{
652+
kcsan_atomic_next(KCSAN_SEQLOCK_REGION_MAX);
653+
return raw_read_seqcount_latch(s);
654+
}
655+
639656
/**
640657
* raw_read_seqcount_latch_retry() - end a seqcount_latch_t read section
641658
* @s: Pointer to seqcount_latch_t
@@ -650,9 +667,34 @@ raw_read_seqcount_latch_retry(const seqcount_latch_t *s, unsigned start)
650667
return unlikely(READ_ONCE(s->seqcount.sequence) != start);
651668
}
652669

670+
/**
671+
* read_seqcount_latch_retry() - end a seqcount_latch_t read section
672+
* @s: Pointer to seqcount_latch_t
673+
* @start: count, from read_seqcount_latch()
674+
*
675+
* Return: true if a read section retry is required, else false
676+
*/
677+
static __always_inline int
678+
read_seqcount_latch_retry(const seqcount_latch_t *s, unsigned start)
679+
{
680+
kcsan_atomic_next(0);
681+
return raw_read_seqcount_latch_retry(s, start);
682+
}
683+
653684
/**
654685
* raw_write_seqcount_latch() - redirect latch readers to even/odd copy
655686
* @s: Pointer to seqcount_latch_t
687+
*/
688+
static __always_inline void raw_write_seqcount_latch(seqcount_latch_t *s)
689+
{
690+
smp_wmb(); /* prior stores before incrementing "sequence" */
691+
s->seqcount.sequence++;
692+
smp_wmb(); /* increment "sequence" before following stores */
693+
}
694+
695+
/**
696+
* write_seqcount_latch_begin() - redirect latch readers to odd copy
697+
* @s: Pointer to seqcount_latch_t
656698
*
657699
* The latch technique is a multiversion concurrency control method that allows
658700
* queries during non-atomic modifications. If you can guarantee queries never
@@ -680,17 +722,11 @@ raw_read_seqcount_latch_retry(const seqcount_latch_t *s, unsigned start)
680722
*
681723
* void latch_modify(struct latch_struct *latch, ...)
682724
* {
683-
* smp_wmb(); // Ensure that the last data[1] update is visible
684-
* latch->seq.sequence++;
685-
* smp_wmb(); // Ensure that the seqcount update is visible
686-
*
725+
* write_seqcount_latch_begin(&latch->seq);
687726
* modify(latch->data[0], ...);
688-
*
689-
* smp_wmb(); // Ensure that the data[0] update is visible
690-
* latch->seq.sequence++;
691-
* smp_wmb(); // Ensure that the seqcount update is visible
692-
*
727+
* write_seqcount_latch(&latch->seq);
693728
* modify(latch->data[1], ...);
729+
* write_seqcount_latch_end(&latch->seq);
694730
* }
695731
*
696732
* The query will have a form like::
@@ -701,13 +737,13 @@ raw_read_seqcount_latch_retry(const seqcount_latch_t *s, unsigned start)
701737
* unsigned seq, idx;
702738
*
703739
* do {
704-
* seq = raw_read_seqcount_latch(&latch->seq);
740+
* seq = read_seqcount_latch(&latch->seq);
705741
*
706742
* idx = seq & 0x01;
707743
* entry = data_query(latch->data[idx], ...);
708744
*
709745
* // This includes needed smp_rmb()
710-
* } while (raw_read_seqcount_latch_retry(&latch->seq, seq));
746+
* } while (read_seqcount_latch_retry(&latch->seq, seq));
711747
*
712748
* return entry;
713749
* }
@@ -731,11 +767,31 @@ raw_read_seqcount_latch_retry(const seqcount_latch_t *s, unsigned start)
731767
* When data is a dynamic data structure; one should use regular RCU
732768
* patterns to manage the lifetimes of the objects within.
733769
*/
734-
static inline void raw_write_seqcount_latch(seqcount_latch_t *s)
770+
static __always_inline void write_seqcount_latch_begin(seqcount_latch_t *s)
735771
{
736-
smp_wmb(); /* prior stores before incrementing "sequence" */
737-
s->seqcount.sequence++;
738-
smp_wmb(); /* increment "sequence" before following stores */
772+
kcsan_nestable_atomic_begin();
773+
raw_write_seqcount_latch(s);
774+
}
775+
776+
/**
777+
* write_seqcount_latch() - redirect latch readers to even copy
778+
* @s: Pointer to seqcount_latch_t
779+
*/
780+
static __always_inline void write_seqcount_latch(seqcount_latch_t *s)
781+
{
782+
raw_write_seqcount_latch(s);
783+
}
784+
785+
/**
786+
* write_seqcount_latch_end() - end a seqcount_latch_t write section
787+
* @s: Pointer to seqcount_latch_t
788+
*
789+
* Marks the end of a seqcount_latch_t writer section, after all copies of the
790+
* latch-protected data have been updated.
791+
*/
792+
static __always_inline void write_seqcount_latch_end(seqcount_latch_t *s)
793+
{
794+
kcsan_nestable_atomic_end();
739795
}
740796

741797
#define __SEQLOCK_UNLOCKED(lockname) \

0 commit comments

Comments
 (0)