* [PATCH] bpf: local_storage: avoid redundant IRQ save on bucket locks
@ 2026-09-16 18:10 Usama Arif
2026-09-16 18:22 ` Kumar Kartikeya Dwivedi
2026-09-16 20:00 ` patchwork-bot+netdevbpf
0 siblings, 2 replies; 7+ messages in thread
From: Usama Arif @ 2026-09-16 18:10 UTC (permalink / raw)
To: ast, andrii, bpf, daniel, eddyz87, emil, ihor.solodrai, jolsa,
justinstitt, linux-kernel, llvm, martin.lau, memxor, morbo,
nathan, ndesaulniers, song, yonghong.song, yatsenko, kernel-team
Cc: Usama Arif
bpf_local_storage_update() takes the map bucket lock while holding
local_storage->lock. bpf_selem_unlink_map() does the same; its only
caller holds local_storage->lock. The outer lock is acquired with
raw_res_spin_lock_irqsave(), so interrupts are already disabled at both
sites.
Using raw_res_spin_lock_irqsave() for the nested lock saves the already
disabled IRQ state and issues another IRQ disable. The matching unlock
tests that saved state before leaving interrupts disabled. On x86-64,
this adds a pushfq/popq/cli sequence and a test/branch around an
unreachable sti to each acquisition.
Use raw_res_spin_lock() and raw_res_spin_unlock() instead. They retain
preemption nesting, memory ordering and resilient-lock bookkeeping. The
outer unlock remains responsible for restoring the caller's IRQ state.
In the tested clang x86-64 build, this removes five executed instructions
from each uncontended nested acquisition. It also shrinks
bpf_local_storage_update() from 1732 to 1702 bytes and bpf_selem_unlink()
from 1030 to 992 bytes. The affected paths are updates that add or replace
an element in existing owner storage and successful unlinks.
Document the owner-lock requirement of bpf_selem_unlink_map() and assert
that interrupts are disabled.
Signed-off-by: Usama Arif <usama.arif@linux.dev>
---
kernel/bpf/bpf_local_storage.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/kernel/bpf/bpf_local_storage.c b/kernel/bpf/bpf_local_storage.c
index 6fc6a4b672b55..4642da062f0f8 100644
--- a/kernel/bpf/bpf_local_storage.c
+++ b/kernel/bpf/bpf_local_storage.c
@@ -240,24 +240,26 @@ void bpf_selem_link_storage_nolock(struct bpf_local_storage *local_storage,
hlist_add_head_rcu(&selem->snode, &local_storage->list);
}
+/* Must be called with the owning local_storage->lock held. */
static int bpf_selem_unlink_map(struct bpf_local_storage_elem *selem)
{
struct bpf_local_storage *local_storage;
struct bpf_local_storage_map *smap;
struct bpf_local_storage_map_bucket *b;
- unsigned long flags;
int err;
+ lockdep_assert_irqs_disabled();
+
local_storage = rcu_dereference_check(selem->local_storage,
bpf_rcu_lock_held());
smap = rcu_dereference_check(SDATA(selem)->smap, bpf_rcu_lock_held());
b = select_bucket(smap, local_storage);
- err = raw_res_spin_lock_irqsave(&b->lock, flags);
+ err = raw_res_spin_lock(&b->lock);
if (err)
return err;
hlist_del_init_rcu(&selem->map_node);
- raw_res_spin_unlock_irqrestore(&b->lock, flags);
+ raw_res_spin_unlock(&b->lock);
return 0;
}
@@ -552,7 +554,7 @@ bpf_local_storage_update(void *owner, struct bpf_local_storage_map *smap,
struct bpf_local_storage *local_storage;
struct bpf_local_storage_map_bucket *b;
HLIST_HEAD(old_selem_free_list);
- unsigned long flags, b_flags;
+ unsigned long flags;
int err;
/* BPF_EXIST and BPF_NOEXIST cannot be both set */
@@ -637,7 +639,8 @@ bpf_local_storage_update(void *owner, struct bpf_local_storage_map *smap,
b = select_bucket(smap, local_storage);
- err = raw_res_spin_lock_irqsave(&b->lock, b_flags);
+ /* local_storage->lock is held, so IRQs are already disabled. */
+ err = raw_res_spin_lock(&b->lock);
if (err)
goto unlock;
@@ -655,7 +658,7 @@ bpf_local_storage_update(void *owner, struct bpf_local_storage_map *smap,
&old_selem_free_list);
}
- raw_res_spin_unlock_irqrestore(&b->lock, b_flags);
+ raw_res_spin_unlock(&b->lock);
unlock:
raw_res_spin_unlock_irqrestore(&local_storage->lock, flags);
free_selem:
--
2.53.0-Meta
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] bpf: local_storage: avoid redundant IRQ save on bucket locks
2026-09-16 18:10 [PATCH] bpf: local_storage: avoid redundant IRQ save on bucket locks Usama Arif
@ 2026-09-16 18:22 ` Kumar Kartikeya Dwivedi
2026-09-16 18:30 ` Amery Hung
` (2 more replies)
2026-09-16 20:00 ` patchwork-bot+netdevbpf
1 sibling, 3 replies; 7+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-09-16 18:22 UTC (permalink / raw)
To: Usama Arif, ast, andrii, bpf, daniel, eddyz87, emil,
ihor.solodrai, jolsa, justinstitt, linux-kernel, llvm,
martin.lau, morbo, nathan, ndesaulniers, song, yonghong.song,
yatsenko, kernel-team, Amery Hung
+Cc Amery
On Wed Sep 16, 2026 at 8:10 PM CEST, Usama Arif wrote:
> bpf_local_storage_update() takes the map bucket lock while holding
> local_storage->lock. bpf_selem_unlink_map() does the same; its only
> caller holds local_storage->lock. The outer lock is acquired with
> raw_res_spin_lock_irqsave(), so interrupts are already disabled at both
> sites.
>
> Using raw_res_spin_lock_irqsave() for the nested lock saves the already
> disabled IRQ state and issues another IRQ disable. The matching unlock
> tests that saved state before leaving interrupts disabled. On x86-64,
> this adds a pushfq/popq/cli sequence and a test/branch around an
> unreachable sti to each acquisition.
>
> Use raw_res_spin_lock() and raw_res_spin_unlock() instead. They retain
> preemption nesting, memory ordering and resilient-lock bookkeeping. The
> outer unlock remains responsible for restoring the caller's IRQ state.
>
> In the tested clang x86-64 build, this removes five executed instructions
> from each uncontended nested acquisition. It also shrinks
> bpf_local_storage_update() from 1732 to 1702 bytes and bpf_selem_unlink()
> from 1030 to 992 bytes. The affected paths are updates that add or replace
> an element in existing owner storage and successful unlinks.
>
> Document the owner-lock requirement of bpf_selem_unlink_map() and assert
> that interrupts are disabled.
>
> Signed-off-by: Usama Arif <usama.arif@linux.dev>
> ---
Makes sense. But did you observe any measurable improvement with this change?
> [...]
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] bpf: local_storage: avoid redundant IRQ save on bucket locks
2026-09-16 18:22 ` Kumar Kartikeya Dwivedi
@ 2026-09-16 18:30 ` Amery Hung
2026-09-16 19:20 ` Usama Arif
2026-09-16 19:22 ` Usama Arif
2 siblings, 0 replies; 7+ messages in thread
From: Amery Hung @ 2026-09-16 18:30 UTC (permalink / raw)
To: Kumar Kartikeya Dwivedi
Cc: Usama Arif, ast, andrii, bpf, daniel, eddyz87, emil,
ihor.solodrai, jolsa, justinstitt, linux-kernel, llvm,
martin.lau, morbo, nathan, ndesaulniers, song, yonghong.song,
yatsenko, kernel-team
On Wed, Sep 16, 2026 at 11:22 AM Kumar Kartikeya Dwivedi
<memxor@gmail.com> wrote:
>
> +Cc Amery
>
> On Wed Sep 16, 2026 at 8:10 PM CEST, Usama Arif wrote:
> > bpf_local_storage_update() takes the map bucket lock while holding
> > local_storage->lock. bpf_selem_unlink_map() does the same; its only
> > caller holds local_storage->lock. The outer lock is acquired with
> > raw_res_spin_lock_irqsave(), so interrupts are already disabled at both
> > sites.
> >
> > Using raw_res_spin_lock_irqsave() for the nested lock saves the already
> > disabled IRQ state and issues another IRQ disable. The matching unlock
> > tests that saved state before leaving interrupts disabled. On x86-64,
> > this adds a pushfq/popq/cli sequence and a test/branch around an
> > unreachable sti to each acquisition.
> >
> > Use raw_res_spin_lock() and raw_res_spin_unlock() instead. They retain
> > preemption nesting, memory ordering and resilient-lock bookkeeping. The
> > outer unlock remains responsible for restoring the caller's IRQ state.
> >
> > In the tested clang x86-64 build, this removes five executed instructions
> > from each uncontended nested acquisition. It also shrinks
> > bpf_local_storage_update() from 1732 to 1702 bytes and bpf_selem_unlink()
> > from 1030 to 992 bytes. The affected paths are updates that add or replace
> > an element in existing owner storage and successful unlinks.
> >
> > Document the owner-lock requirement of bpf_selem_unlink_map() and assert
> > that interrupts are disabled.
> >
> > Signed-off-by: Usama Arif <usama.arif@linux.dev>
> > ---
>
> Makes sense. But did you observe any measurable improvement with this change?
>
Same question, but the change looks right to me.
> > [...]
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] bpf: local_storage: avoid redundant IRQ save on bucket locks
2026-09-16 18:22 ` Kumar Kartikeya Dwivedi
2026-09-16 18:30 ` Amery Hung
@ 2026-09-16 19:20 ` Usama Arif
2026-09-16 19:22 ` Usama Arif
2 siblings, 0 replies; 7+ messages in thread
From: Usama Arif @ 2026-09-16 19:20 UTC (permalink / raw)
To: Kumar Kartikeya Dwivedi, ast, andrii, bpf, daniel, eddyz87, emil,
ihor.solodrai, jolsa, justinstitt, linux-kernel, llvm,
martin.lau, morbo, nathan, ndesaulniers, song, yonghong.song,
yatsenko, kernel-team, Amery Hung
On 16/09/2026 19:22, Kumar Kartikeya Dwivedi wrote:
> +Cc Amery
>
> On Wed Sep 16, 2026 at 8:10 PM CEST, Usama Arif wrote:
>> bpf_local_storage_update() takes the map bucket lock while holding
>> local_storage->lock. bpf_selem_unlink_map() does the same; its only
>> caller holds local_storage->lock. The outer lock is acquired with
>> raw_res_spin_lock_irqsave(), so interrupts are already disabled at both
>> sites.
>>
>> Using raw_res_spin_lock_irqsave() for the nested lock saves the already
>> disabled IRQ state and issues another IRQ disable. The matching unlock
>> tests that saved state before leaving interrupts disabled. On x86-64,
>> this adds a pushfq/popq/cli sequence and a test/branch around an
>> unreachable sti to each acquisition.
>>
>> Use raw_res_spin_lock() and raw_res_spin_unlock() instead. They retain
>> preemption nesting, memory ordering and resilient-lock bookkeeping. The
>> outer unlock remains responsible for restoring the caller's IRQ state.
>>
>> In the tested clang x86-64 build, this removes five executed instructions
>> from each uncontended nested acquisition. It also shrinks
>> bpf_local_storage_update() from 1732 to 1702 bytes and bpf_selem_unlink()
>> from 1030 to 992 bytes. The affected paths are updates that add or replace
>> an element in existing owner storage and successful unlinks.
>>
>> Document the owner-lock requirement of bpf_selem_unlink_map() and assert
>> that interrupts are disabled.
>>
>> Signed-off-by: Usama Arif <usama.arif@linux.dev>
>> ---
>
> Makes sense. But did you observe any measurable improvement with this change?
Meta fleet wide profile shows bpf_local_storage_update() as one of the more expensive
bpf functions in the fleet. I saw it in production when profiling a hhvm workload as
well.
The main argument for the patch was reduced number of instructions executed in
this expensive path that I see in disassembly (which is mentioned in the 2nd paragraph)
and better code hygiene as it doesnt make sense to to save irq again. I would imagine
this patch alone wont move the needle in application metrics, but would make this function
cheaper (hopefully :)) fleetwide.
>
>> [...]
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] bpf: local_storage: avoid redundant IRQ save on bucket locks
2026-09-16 18:22 ` Kumar Kartikeya Dwivedi
2026-09-16 18:30 ` Amery Hung
2026-09-16 19:20 ` Usama Arif
@ 2026-09-16 19:22 ` Usama Arif
2026-09-16 19:29 ` Amery Hung
2 siblings, 1 reply; 7+ messages in thread
From: Usama Arif @ 2026-09-16 19:22 UTC (permalink / raw)
To: Kumar Kartikeya Dwivedi, ast, andrii, bpf, daniel, eddyz87, emil,
ihor.solodrai, jolsa, justinstitt, linux-kernel, llvm,
martin.lau, morbo, nathan, ndesaulniers, song, yonghong.song,
yatsenko, kernel-team, Amery Hung
On 16/09/2026 19:22, Kumar Kartikeya Dwivedi wrote:
> +Cc Amery
>
> On Wed Sep 16, 2026 at 8:10 PM CEST, Usama Arif wrote:
>> bpf_local_storage_update() takes the map bucket lock while holding
>> local_storage->lock. bpf_selem_unlink_map() does the same; its only
>> caller holds local_storage->lock. The outer lock is acquired with
>> raw_res_spin_lock_irqsave(), so interrupts are already disabled at both
>> sites.
>>
>> Using raw_res_spin_lock_irqsave() for the nested lock saves the already
>> disabled IRQ state and issues another IRQ disable. The matching unlock
>> tests that saved state before leaving interrupts disabled. On x86-64,
>> this adds a pushfq/popq/cli sequence and a test/branch around an
>> unreachable sti to each acquisition.
>>
>> Use raw_res_spin_lock() and raw_res_spin_unlock() instead. They retain
>> preemption nesting, memory ordering and resilient-lock bookkeeping. The
>> outer unlock remains responsible for restoring the caller's IRQ state.
>>
>> In the tested clang x86-64 build, this removes five executed instructions
>> from each uncontended nested acquisition. It also shrinks
>> bpf_local_storage_update() from 1732 to 1702 bytes and bpf_selem_unlink()
>> from 1030 to 992 bytes. The affected paths are updates that add or replace
>> an element in existing owner storage and successful unlinks.
>>
>> Document the owner-lock requirement of bpf_selem_unlink_map() and assert
>> that interrupts are disabled.
>>
>> Signed-off-by: Usama Arif <usama.arif@linux.dev>
>> ---
>
> Makes sense. But did you observe any measurable improvement with this change?
Meta fleet wide profile shows bpf_local_storage_update() as one of the more expensive
bpf functions in the fleet. I saw it in production when profiling a hhvm workload as
well.
The main argument for the patch was reduced number of instructions executed in
this expensive path that I see in disassembly (which is mentioned in the 2nd paragraph)
and better code hygiene as it doesnt make sense to to save irq again. I would imagine
this patch alone wont move the needle in application metrics, but would make this function
cheaper (hopefully :)) fleetwide.
>
>> [...]
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] bpf: local_storage: avoid redundant IRQ save on bucket locks
2026-09-16 19:22 ` Usama Arif
@ 2026-09-16 19:29 ` Amery Hung
0 siblings, 0 replies; 7+ messages in thread
From: Amery Hung @ 2026-09-16 19:29 UTC (permalink / raw)
To: Usama Arif
Cc: Kumar Kartikeya Dwivedi, ast, andrii, bpf, daniel, eddyz87, emil,
ihor.solodrai, jolsa, justinstitt, linux-kernel, llvm,
martin.lau, morbo, nathan, ndesaulniers, song, yonghong.song,
yatsenko, kernel-team
On Wed, Sep 16, 2026 at 12:22 PM Usama Arif <usama.arif@linux.dev> wrote:
>
>
>
> On 16/09/2026 19:22, Kumar Kartikeya Dwivedi wrote:
> > +Cc Amery
> >
> > On Wed Sep 16, 2026 at 8:10 PM CEST, Usama Arif wrote:
> >> bpf_local_storage_update() takes the map bucket lock while holding
> >> local_storage->lock. bpf_selem_unlink_map() does the same; its only
> >> caller holds local_storage->lock. The outer lock is acquired with
> >> raw_res_spin_lock_irqsave(), so interrupts are already disabled at both
> >> sites.
> >>
> >> Using raw_res_spin_lock_irqsave() for the nested lock saves the already
> >> disabled IRQ state and issues another IRQ disable. The matching unlock
> >> tests that saved state before leaving interrupts disabled. On x86-64,
> >> this adds a pushfq/popq/cli sequence and a test/branch around an
> >> unreachable sti to each acquisition.
> >>
> >> Use raw_res_spin_lock() and raw_res_spin_unlock() instead. They retain
> >> preemption nesting, memory ordering and resilient-lock bookkeeping. The
> >> outer unlock remains responsible for restoring the caller's IRQ state.
> >>
> >> In the tested clang x86-64 build, this removes five executed instructions
> >> from each uncontended nested acquisition. It also shrinks
> >> bpf_local_storage_update() from 1732 to 1702 bytes and bpf_selem_unlink()
> >> from 1030 to 992 bytes. The affected paths are updates that add or replace
> >> an element in existing owner storage and successful unlinks.
> >>
> >> Document the owner-lock requirement of bpf_selem_unlink_map() and assert
> >> that interrupts are disabled.
> >>
> >> Signed-off-by: Usama Arif <usama.arif@linux.dev>
> >> ---
> >
> > Makes sense. But did you observe any measurable improvement with this change?
>
> Meta fleet wide profile shows bpf_local_storage_update() as one of the more expensive
> bpf functions in the fleet. I saw it in production when profiling a hhvm workload as
> well.
>
> The main argument for the patch was reduced number of instructions executed in
> this expensive path that I see in disassembly (which is mentioned in the 2nd paragraph)
> and better code hygiene as it doesnt make sense to to save irq again. I would imagine
> this patch alone wont move the needle in application metrics, but would make this function
> cheaper (hopefully :)) fleetwide.
>
Reviewed-by: Amery Hung <ameryhung@gmail.com>
>
> >
> >> [...]
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] bpf: local_storage: avoid redundant IRQ save on bucket locks
2026-09-16 18:10 [PATCH] bpf: local_storage: avoid redundant IRQ save on bucket locks Usama Arif
2026-09-16 18:22 ` Kumar Kartikeya Dwivedi
@ 2026-09-16 20:00 ` patchwork-bot+netdevbpf
1 sibling, 0 replies; 7+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-09-16 20:00 UTC (permalink / raw)
To: Usama Arif
Cc: ast, andrii, bpf, daniel, eddyz87, emil, ihor.solodrai, jolsa,
justinstitt, linux-kernel, llvm, martin.lau, memxor, morbo,
nathan, ndesaulniers, song, yonghong.song, yatsenko, kernel-team
Hello:
This patch was applied to bpf/bpf-next.git (master)
by Kumar Kartikeya Dwivedi <memxor@gmail.com>:
On Wed, 16 Sep 2026 11:10:01 -0700 you wrote:
> bpf_local_storage_update() takes the map bucket lock while holding
> local_storage->lock. bpf_selem_unlink_map() does the same; its only
> caller holds local_storage->lock. The outer lock is acquired with
> raw_res_spin_lock_irqsave(), so interrupts are already disabled at both
> sites.
>
> Using raw_res_spin_lock_irqsave() for the nested lock saves the already
> disabled IRQ state and issues another IRQ disable. The matching unlock
> tests that saved state before leaving interrupts disabled. On x86-64,
> this adds a pushfq/popq/cli sequence and a test/branch around an
> unreachable sti to each acquisition.
>
> [...]
Here is the summary with links:
- bpf: local_storage: avoid redundant IRQ save on bucket locks
https://git.kernel.org/bpf/bpf-next/c/10c4f610b215
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-09-16 20:01 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-16 18:10 [PATCH] bpf: local_storage: avoid redundant IRQ save on bucket locks Usama Arif
2026-09-16 18:22 ` Kumar Kartikeya Dwivedi
2026-09-16 18:30 ` Amery Hung
2026-09-16 19:20 ` Usama Arif
2026-09-16 19:22 ` Usama Arif
2026-09-16 19:29 ` Amery Hung
2026-09-16 20:00 ` patchwork-bot+netdevbpf
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®