BPF List
 help / color / mirror / Atom feed
* [BUG: 6.6.y] bpf fentry hook on _raw_spin_lock_irqsave triggers hard lockup
@ 2026-07-29  7:53 Feng Yang
  2026-07-29  8:29 ` Greg KH
  0 siblings, 1 reply; 2+ messages in thread
From: Feng Yang @ 2026-07-29  7:53 UTC (permalink / raw)
  To: bpf, stable; +Cc: andrii, eddyz87, ast, daniel, memxor, martin.lau, song

When attaching fentry programs to _raw_spin_lock_irqsave/_raw_spin_unlock_irqrestore on
the v6.6 kernel and using the BPF ring buffer within BPF programs, we encounter a hard LOCKUP.

Reproducible BPF code is shown below:

static inline int test(void *ctx)
{
        struct event *event;

        event = reserve_buf(sizeof(*event));
        if (!event)
                return 0;

        submit_buf(ctx, event, sizeof(*event));

        return 0;
}

SEC("fentry/_raw_spin_lock_irqsave")
int BPF_PROG(aa)
{
        return test(ctx);
}

SEC("fentry/_raw_spin_unlock_irqrestore")
int BPF_PROG(bb)
{
        return test(ctx);
}

We suspect the hard LOCKUP is caused by the call chain:
aa->test->reserve_buf->_raw_spin_lock_irqsave->_raw_spin_unlock_irqrestore->bb->test->reserve_buf->_raw_spin_lock_irqsave.

Mainline has merged the rqspinlock patchset
(https://lore.kernel.org/all/20250411101759.4061366-1-memxor@gmail.com/)
which resolves this issue. Should we backport the fix?

Alternatively, would a fix modeled after this patch
https://lore.kernel.org/bpf/20201029071925.3103400-3-songliubraving@fb.com/
as outlined below be viable?

--- a/kernel/bpf/ringbuf.c
+++ b/kernel/bpf/ringbuf.c
@@ -30,6 +30,7 @@ struct bpf_ringbuf {
 	struct page **pages;
 	int nr_pages;
 	raw_spinlock_t spinlock ____cacheline_aligned_in_smp;
+	int __percpu *ringbuf_lock;
 	/* For user-space producer ring buffers, an atomic_t busy bit is used
 	 * to synchronize access to the ring buffers in the kernel, rather than
 	 * the spinlock that is used for kernel-producer ring buffers. This is
@@ -165,6 +166,8 @@ static void bpf_ringbuf_notify(struct irq_work *work)
  * considering that the maximum value of data_sz is (4GB - 1), there
  * will be no overflow, so just note the size limit in the comments.
  */
+static void bpf_ringbuf_free(struct bpf_ringbuf *rb);
+
 static struct bpf_ringbuf *bpf_ringbuf_alloc(size_t data_sz, int numa_node)
 {
 	struct bpf_ringbuf *rb;
@@ -178,6 +181,12 @@ static struct bpf_ringbuf *bpf_ringbuf_alloc(size_t data_sz, int numa_node)
 	init_waitqueue_head(&rb->waitq);
 	init_irq_work(&rb->work, bpf_ringbuf_notify);
 
+	rb->ringbuf_lock = __alloc_percpu_gfp(sizeof(int), sizeof(int), GFP_USER);
+	if (!rb->ringbuf_lock) {
+		bpf_ringbuf_free(rb);
+		return NULL;
+	}
+
 	rb->mask = data_sz - 1;
 	rb->consumer_pos = 0;
 	rb->producer_pos = 0;
@@ -215,6 +224,7 @@ static struct bpf_map *ringbuf_map_alloc(union bpf_attr *attr)
 
 static void bpf_ringbuf_free(struct bpf_ringbuf *rb)
 {
+	free_percpu(rb->ringbuf_lock);
 	irq_work_sync(&rb->work);
 
 	/* copy pages pointer and nr_pages to local variable, as we are going
@@ -418,9 +428,19 @@ static void *__bpf_ringbuf_reserve(struct bpf_ringbuf *rb, u64 size)
 
 	cons_pos = smp_load_acquire(&rb->consumer_pos);
 
+	preempt_disable();
+	if (unlikely(__this_cpu_inc_return(*rb->ringbuf_lock) != 1)) {
+		__this_cpu_dec(*rb->ringbuf_lock);
+		preempt_enable();
+		return NULL;
+	}
+
 	if (in_nmi()) {
-		if (!raw_spin_trylock_irqsave(&rb->spinlock, flags))
+		if (!raw_spin_trylock_irqsave(&rb->spinlock, flags)) {
+			__this_cpu_dec(*rb->ringbuf_lock);
+			preempt_enable();
 			return NULL;
+		}
 	} else {
 		raw_spin_lock_irqsave(&rb->spinlock, flags);
 	}
@@ -449,6 +469,8 @@ static void *__bpf_ringbuf_reserve(struct bpf_ringbuf *rb, u64 size)
 	if (new_prod_pos - cons_pos > rb->mask ||
 	    new_prod_pos - pend_pos > rb->mask) {
 		raw_spin_unlock_irqrestore(&rb->spinlock, flags);
+		__this_cpu_dec(*rb->ringbuf_lock);
+		preempt_enable();
 		return NULL;
 	}
 
@@ -461,6 +483,8 @@ static void *__bpf_ringbuf_reserve(struct bpf_ringbuf *rb, u64 size)
 	smp_store_release(&rb->producer_pos, new_prod_pos);
 
 	raw_spin_unlock_irqrestore(&rb->spinlock, flags);
+	__this_cpu_dec(*rb->ringbuf_lock);
+	preempt_enable();
 
 	return (void *)hdr + BPF_RINGBUF_HDR_SZ;
 }

Thanks,
Feng


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-07-29  8:29 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-29  7:53 [BUG: 6.6.y] bpf fentry hook on _raw_spin_lock_irqsave triggers hard lockup Feng Yang
2026-07-29  8:29 ` Greg KH

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox