On Tue, 4 Mar 2025 at 12:21, Peter Zijlstra <peterz@xxxxxxxxxxxxx> wrote: > > On Tue, Mar 04, 2025 at 10:20:59AM +0100, Marco Elver wrote: > > > === Initial Uses === > > > > With this initial series, the following synchronization primitives are > > supported: `raw_spinlock_t`, `spinlock_t`, `rwlock_t`, `mutex`, > > `seqlock_t`, `bit_spinlock`, RCU, SRCU (`srcu_struct`), `rw_semaphore`, > > `local_lock_t`, `ww_mutex`. > > Wasn't there a limitation wrt recursion -- specifically RCU is very much > a recursive lock and TS didn't really fancy that? Yup, I mentioned that in the rcu patch. Make it more prominent in documentation? > > - Rename __var_guarded_by to simply __guarded_by. Initially the idea > > was to be explicit about if the variable itself or the pointed-to > > data is guarded, but in the long-term, making this shorter might be > > better. > > > > - Likewise rename __ref_guarded_by to __pt_guarded_by. > > Shorter is better :-) > > Anyway; I think I would like to start talking about extensions for these > asap. > > Notably I feel like we should have a means to annotate the rules for > access/read vs modify/write to a variable. > > The obvious case is RCU; where holding RCU is sufficient to read, but > modification requires a 'real' lock. This is not something that can be > currently expressed. It can. It distinguishes between holding shared/read locks and exclusive/read-write locks. RCU is is a bit special because we also have rcu_dereference() and rcu_assign_pointer() and such, but in general if you only hold a "shared capability" e.g. the RCU read lock only, it won't let you write to __guarded_by variables. Again, the RCU case is special because updating RCU-guarded can be done any number of ways, so I had to make rcu_assign_pointer() a bit more relaxed. But besides RCU, the distinction between holding a lock exclusively or shared does what one would expect: holding the lock exclusively lets you write, and holding it shared only lets you only read a __guarded_by() member. > The other is the lock pattern I touched upon the other day, where > reading is permitted when holding one of two locks, while writing > requires holding both locks. > > Being able to explicitly write that in the __guarded_by() annotations is > the cleanest way I think. Simpler forms of this are possible if you stack __guarded_by(): you must hold both locks exclusively to write, otherwise you can only read (but must still hold both locks "shared", or "shared"+"exclusive"). The special case regarding "hold lock A -OR- B to read" is problematic of course - that can be solved by designing lock-wrappers that "fake acquire" some lock, or we do design some extension. We can go off and propose something to the Clang maintainers, but I fear that there are only few cases where we need __guarded_by(A OR B). If you say we need an extension, then we need a list of requirements that we can go and design a clear and implementable extension. In general, yes, the analysis imposes additional constraints, and not all kernel locking patterns will be expressible (if ever). But a lot of the "regular" code (drivers!) can be opted in today. Thanks, -- Marco