Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'lkmm.2024.07.12a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu

Pull memory model updates from Paul McKenney:
"lkmm: Fix corner-case locking bug and improve documentation

A simple but odd single-process litmus test acquires and immediately
releases a lock, then calls spin_is_locked(). LKMM acts if it was a
deadlock due to an assumption that spin_is_locked() will follow a
spin_lock() or some other process's spin_unlock(). This litmus test
manages to violate this assumption because the spin_is_locked()
follows the same process's spin_unlock().

This series fixes this bug, reorganizes and optimizes the lock.cat
model, and updates documentation"

* tag 'lkmm.2024.07.12a' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu:
tools/memory-model: Code reorganization in lock.cat
tools/memory-model: Fix bug in lock.cat
tools/memory-model: Add access-marking.txt to README
tools/memory-model: Add KCSAN LF mentorship session citation

+48 -26
+4
tools/memory-model/Documentation/README
··· 47 47 README 48 48 This file. 49 49 50 + access-marking.txt 51 + Guidelines for marking intentionally concurrent accesses to 52 + shared memory. 53 + 50 54 cheatsheet.txt 51 55 Quick-reference guide to the Linux-kernel memory model. 52 56
+7 -3
tools/memory-model/Documentation/access-marking.txt
··· 6 6 not use read-modify-write atomic operations. It also describes how to 7 7 document these accesses, both with comments and with special assertions 8 8 processed by the Kernel Concurrency Sanitizer (KCSAN). This discussion 9 - builds on an earlier LWN article [1]. 9 + builds on an earlier LWN article [1] and Linux Foundation mentorship 10 + session [2]. 10 11 11 12 12 13 ACCESS-MARKING OPTIONS ··· 32 31 WRITE_ONCE(a, b + data_race(c + d) + READ_ONCE(e)); 33 32 34 33 Neither plain C-language accesses nor data_race() (#1 and #2 above) place 35 - any sort of constraint on the compiler's choice of optimizations [2]. 34 + any sort of constraint on the compiler's choice of optimizations [3]. 36 35 In contrast, READ_ONCE() and WRITE_ONCE() (#3 and #4 above) restrict the 37 36 compiler's use of code-motion and common-subexpression optimizations. 38 37 Therefore, if a given access is involved in an intentional data race, ··· 595 594 [1] "Concurrency bugs should fear the big bad data-race detector (part 2)" 596 595 https://lwn.net/Articles/816854/ 597 596 598 - [2] "Who's afraid of a big bad optimizing compiler?" 597 + [2] "The Kernel Concurrency Sanitizer" 598 + https://www.linuxfoundation.org/webinars/the-kernel-concurrency-sanitizer 599 + 600 + [3] "Who's afraid of a big bad optimizing compiler?" 599 601 https://lwn.net/Articles/793253/
+37 -23
tools/memory-model/lock.cat
··· 54 54 *) 55 55 empty ([LKW] ; po-loc ; [LKR]) \ (po-loc ; [UL] ; po-loc) as lock-nest 56 56 57 + (* 58 + * In the same way, spin_is_locked() inside a critical section must always 59 + * return True (no RU events can be in a critical section for the same lock). 60 + *) 61 + empty ([LKW] ; po-loc ; [RU]) \ (po-loc ; [UL] ; po-loc) as nested-is-locked 62 + 57 63 (* The final value of a spinlock should not be tested *) 58 64 flag ~empty [FW] ; loc ; [ALL-LOCKS] as lock-final 59 65 ··· 85 79 (* rfi for LF events: link each LKW to the LF events in its critical section *) 86 80 let rfi-lf = ([LKW] ; po-loc ; [LF]) \ ([LKW] ; po-loc ; [UL] ; po-loc) 87 81 88 - (* rfe for LF events *) 82 + (* Utility macro to convert a single pair to a single-edge relation *) 83 + let pair-to-relation p = p ++ 0 84 + 85 + (* 86 + * If a given LF event e is outside a critical section, it cannot read 87 + * internally but it may read from an LKW event in another thread. 88 + * Compute the relation containing these possible edges. 89 + *) 90 + let possible-rfe-noncrit-lf e = (LKW * {e}) & loc & ext 91 + 92 + (* Compute set of sets of possible rfe edges for LF events *) 89 93 let all-possible-rfe-lf = 90 94 (* 91 - * Given an LF event r, compute the possible rfe edges for that event 92 - * (all those starting from LKW events in other threads), 93 - * and then convert that relation to a set of single-edge relations. 95 + * Convert the possible-rfe-noncrit-lf relation for e 96 + * to a set of single edges 94 97 *) 95 - let possible-rfe-lf r = 96 - let pair-to-relation p = p ++ 0 97 - in map pair-to-relation ((LKW * {r}) & loc & ext) 98 - (* Do this for each LF event r that isn't in rfi-lf *) 99 - in map possible-rfe-lf (LF \ range(rfi-lf)) 98 + let set-of-singleton-rfe-lf e = 99 + map pair-to-relation (possible-rfe-noncrit-lf e) 100 + (* Do this for each LF event e that isn't in rfi-lf *) 101 + in map set-of-singleton-rfe-lf (LF \ range(rfi-lf)) 100 102 101 103 (* Generate all rf relations for LF events *) 102 104 with rfe-lf from cross(all-possible-rfe-lf) 103 105 let rf-lf = rfe-lf | rfi-lf 104 106 105 107 (* 106 - * RU, i.e., spin_is_locked() returning False, is slightly different. 107 - * We rely on the memory model to rule out cases where spin_is_locked() 108 - * within one of the lock's critical sections returns False. 108 + * A given RU event e may read internally from the last po-previous UL, 109 + * or it may read from a UL event in another thread or the initial write. 110 + * Compute the relation containing these possible edges. 109 111 *) 112 + let possible-rf-ru e = (((UL * {e}) & po-loc) \ 113 + ([UL] ; po-loc ; [UL] ; po-loc)) | 114 + (((UL | IW) * {e}) & loc & ext) 110 115 111 - (* rfi for RU events: an RU may read from the last po-previous UL *) 112 - let rfi-ru = ([UL] ; po-loc ; [RU]) \ ([UL] ; po-loc ; [LKW] ; po-loc) 113 - 114 - (* rfe for RU events: an RU may read from an external UL or the initial write *) 115 - let all-possible-rfe-ru = 116 - let possible-rfe-ru r = 117 - let pair-to-relation p = p ++ 0 118 - in map pair-to-relation (((UL | IW) * {r}) & loc & ext) 119 - in map possible-rfe-ru RU 116 + (* Compute set of sets of possible rf edges for RU events *) 117 + let all-possible-rf-ru = 118 + (* Convert the possible-rf-ru relation for e to a set of single edges *) 119 + let set-of-singleton-rf-ru e = 120 + map pair-to-relation (possible-rf-ru e) 121 + (* Do this for each RU event e *) 122 + in map set-of-singleton-rf-ru RU 120 123 121 124 (* Generate all rf relations for RU events *) 122 - with rfe-ru from cross(all-possible-rfe-ru) 123 - let rf-ru = rfe-ru | rfi-ru 125 + with rf-ru from cross(all-possible-rf-ru) 124 126 125 127 (* Final rf relation *) 126 128 let rf = rf | rf-lf | rf-ru