Skip to content

Helper function bpf_spin_lock

v5.1

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 types BPF_MAP_TYPE_HASH and BPF_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 and BPF_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 the bpf_spin_lock() and bpf_spin_unlock() helpers. Loading or storing data into the struct 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 have struct 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 the bpf_spin_lock field to user space.
  • Syscall with command BPF_MAP_UPDATE_ELEM, or update from a BPF program, do not update the bpf_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:

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";