On Wed, Nov 09, 2022 at 05:07:44AM IST, Andrii Nakryiko wrote: > On Mon, Nov 7, 2022 at 3:10 PM Kumar Kartikeya Dwivedi <memxor@xxxxxxxxx> wrote: > > > > Global variables reside in maps accessible using direct_value_addr > > callbacks, so giving each load instruction's rewrite a unique reg->id > > disallows us from holding locks which are global. > > > > The reason for preserving reg->id as a unique value for registers that > > may point to spin lock is that two separate lookups are treated as two > > separate memory regions, and any possible aliasing is ignored for the > > purposes of spin lock correctness. > > > > This is not great especially for the global variable case, which are > > served from maps that have max_entries == 1, i.e. they always lead to > > map values pointing into the same map value. > > > > So refactor the active_spin_lock into a 'active_lock' structure which > > represents the lock identity, and instead of the reg->id, remember two > > fields, a pointer and the reg->id. The pointer will store reg->map_ptr > > or reg->btf. It's only necessary to distinguish for the id == 0 case of > > global variables, but always setting the pointer to a non-NULL value and > > using the pointer to check whether the lock is held simplifies code in > > the verifier. > > > > This is generic enough to allow it for global variables, map lookups, > > and local kptr registers at the same time. > > > > Note that while whether a lock is held can be answered by just comparing > > active_lock.ptr to NULL, to determine whether the register is pointing > > to the same held lock requires comparing _both_ ptr and id. > > > > Finally, as a result of this refactoring, pseudo load instructions are > > not given a unique reg->id, as they are doing lookup for the same map > > value (max_entries is never greater than 1). > > > > Essentially, we consider that the tuple of (ptr, id) will always be > > unique for any kind of argument to bpf_spin_{lock,unlock}. > > > > Note that this can be extended in the future to also remember offset > > used for locking, so that we can introduce multiple bpf_spin_lock fields > > in the same allocation. > > > > Signed-off-by: Kumar Kartikeya Dwivedi <memxor@xxxxxxxxx> > > --- > > include/linux/bpf_verifier.h | 5 ++++- > > kernel/bpf/verifier.c | 41 ++++++++++++++++++++++++------------ > > 2 files changed, 32 insertions(+), 14 deletions(-) > > > > diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h > > index 1a32baa78ce2..70cccac62a15 100644 > > --- a/include/linux/bpf_verifier.h > > +++ b/include/linux/bpf_verifier.h > > @@ -323,7 +323,10 @@ struct bpf_verifier_state { > > u32 branches; > > u32 insn_idx; > > u32 curframe; > > - u32 active_spin_lock; > > + struct { > > + void *ptr; > > document that this could be either struct bpf_map or struct btf > pointer, at least? > Ack, I'll add a comment. Though it's not really meant to be used (i.e. turned back into a pointer to them), it's just an 'identity' pointer.