Helper function bpf_spin_lock
Acquire a spinlock represented by the pointer lock
, which is
stored as part of a value of a map. Taking the lock allows to
safely update the rest of the fields in that value. The
spinlock can (and must) later be released with a call to
bpf_spin_unlock
.
Definition
Copyright (c) 2015 The Libbpf Authors. All rights reserved.
static long (* const bpf_spin_lock)(struct bpf_spin_lock *lock) = (void *) 93;
Usage
Spinlocks in BPF programs come with a number of restrictions and constraints:
bpf_spin_lock
objects are only allowed inside maps of typesBPF_MAP_TYPE_HASH
andBPF_MAP_TYPE_ARRAY
(this list could be extended in the future).- BTF description of the map is mandatory.
- The BPF program can take ONE lock at a time, since taking two or more could cause dead locks.
- Only one
struct bpf_spin_lock
is allowed per map element. - When the lock is taken, calls (either BPF to BPF or helpers) are not allowed.
- The
BPF_LD_ABS
andBPF_LD_IND
instructions are not allowed inside a spinlock-ed region. - The BPF program MUST call
bpf_spin_unlock()
to release the lock, on all execution paths, before it returns. - The BPF program can access
struct bpf_spin_lock
only via thebpf_spin_lock()
andbpf_spin_unlock()
helpers. Loading or storing data into thestruct bpf_spin_lock lock;
field of a map is not allowed. - To use the
bpf_spin_lock()
helper, the BTF description of the map value must be a struct and havestruct bpf_spin_lock anyname;
field at the top level. Nested lock inside another struct is not allowed. - The
struct bpf_spin_lock lock
field in a map value must be aligned on a multiple of 4 bytes in that value. - Syscall with command
BPF_MAP_LOOKUP_ELEM
does not copy thebpf_spin_lock
field to user space. - Syscall with command
BPF_MAP_UPDATE_ELEM
, or update from a BPF program, do not update thebpf_spin_lock
field. bpf_spin_lock
cannot be on the stack or inside a networking packet (it can only be inside of a map values).bpf_spin_lock
is available to root only.- Tracing programs and socket filter programs cannot use
bpf_spin_lock()
due to insufficient preemption checks (but this may change in the future). bpf_spin_lock
is not allowed in inner maps of map-in-map.
Program types
This helper call can be used in the following program types:
BPF_PROG_TYPE_CGROUP_DEVICE
BPF_PROG_TYPE_CGROUP_SKB
BPF_PROG_TYPE_CGROUP_SOCK
BPF_PROG_TYPE_CGROUP_SOCKOPT
BPF_PROG_TYPE_CGROUP_SOCK_ADDR
BPF_PROG_TYPE_CGROUP_SYSCTL
BPF_PROG_TYPE_FLOW_DISSECTOR
BPF_PROG_TYPE_LSM
BPF_PROG_TYPE_LWT_IN
BPF_PROG_TYPE_LWT_OUT
BPF_PROG_TYPE_LWT_SEG6LOCAL
BPF_PROG_TYPE_LWT_XMIT
BPF_PROG_TYPE_SCHED_ACT
BPF_PROG_TYPE_SCHED_CLS
BPF_PROG_TYPE_SK_LOOKUP
BPF_PROG_TYPE_SK_MSG
BPF_PROG_TYPE_SK_REUSEPORT
BPF_PROG_TYPE_SK_SKB
BPF_PROG_TYPE_SOCK_OPS
BPF_PROG_TYPE_SYSCALL
BPF_PROG_TYPE_TRACING
BPF_PROG_TYPE_XDP
Note
bpf_spin_lock
also can't be used if the program has been loaded with the BPF_F_SLEEPABLE
flag.
Example
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2020 Facebook
#include <linux/ptrace.h>
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#define VAR_NUM 2
struct hmap_elem {
struct bpf_spin_lock lock;
int var[VAR_NUM];
};
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1);
__type(key, __u32);
__type(value, struct hmap_elem);
} hash_map SEC(".maps");
SEC("freplace/handle_kprobe")
int new_handle_kprobe(struct pt_regs *ctx)
{
struct hmap_elem *val;
int key = 0;
val = bpf_map_lookup_elem(&hash_map, &key);
if (!val)
return 1;
/* spin_lock in hash map */
bpf_spin_lock(&val->lock);
val->var[0] = 99;
bpf_spin_unlock(&val->lock);
return 0;
}
char _license[] SEC("license") = "GPL";