Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

bpf: Convert bpf_selem_unlink to failable

To prepare changing both bpf_local_storage_map_bucket::lock and
bpf_local_storage::lock to rqspinlock, convert bpf_selem_unlink() to
failable. It still always succeeds and returns 0 until the change
happens. No functional change.

Open code bpf_selem_unlink_storage() in the only caller,
bpf_selem_unlink(), since unlink_map and unlink_storage must be done
together after all the necessary locks are acquired.

For bpf_local_storage_map_free(), ignore the return from
bpf_selem_unlink() for now. A later patch will allow it to unlink selems
even when failing to acquire locks.

Acked-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Amery Hung <ameryhung@gmail.com>
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Link: https://patch.msgid.link/20260205222916.1788211-5-ameryhung@gmail.com

authored by

Amery Hung and committed by
Martin KaFai Lau
403e935f fd103ffc

+39 -49
+1 -1
include/linux/bpf_local_storage.h
··· 176 176 void bpf_selem_link_storage_nolock(struct bpf_local_storage *local_storage, 177 177 struct bpf_local_storage_elem *selem); 178 178 179 - void bpf_selem_unlink(struct bpf_local_storage_elem *selem, bool reuse_now); 179 + int bpf_selem_unlink(struct bpf_local_storage_elem *selem, bool reuse_now); 180 180 181 181 int bpf_selem_link_map(struct bpf_local_storage_map *smap, 182 182 struct bpf_local_storage *local_storage,
+1 -2
kernel/bpf/bpf_cgrp_storage.c
··· 118 118 if (!sdata) 119 119 return -ENOENT; 120 120 121 - bpf_selem_unlink(SELEM(sdata), false); 122 - return 0; 121 + return bpf_selem_unlink(SELEM(sdata), false); 123 122 } 124 123 125 124 static long bpf_cgrp_storage_delete_elem(struct bpf_map *map, void *key)
+1 -3
kernel/bpf/bpf_inode_storage.c
··· 110 110 if (!sdata) 111 111 return -ENOENT; 112 112 113 - bpf_selem_unlink(SELEM(sdata), false); 114 - 115 - return 0; 113 + return bpf_selem_unlink(SELEM(sdata), false); 116 114 } 117 115 118 116 static long bpf_fd_inode_storage_delete_elem(struct bpf_map *map, void *key)
+34 -37
kernel/bpf/bpf_local_storage.c
··· 308 308 return free_local_storage; 309 309 } 310 310 311 - static void bpf_selem_unlink_storage(struct bpf_local_storage_elem *selem, 312 - bool reuse_now) 313 - { 314 - struct bpf_local_storage *local_storage; 315 - bool free_local_storage = false; 316 - HLIST_HEAD(selem_free_list); 317 - unsigned long flags; 318 - 319 - if (unlikely(!selem_linked_to_storage_lockless(selem))) 320 - /* selem has already been unlinked from sk */ 321 - return; 322 - 323 - local_storage = rcu_dereference_check(selem->local_storage, 324 - bpf_rcu_lock_held()); 325 - 326 - raw_spin_lock_irqsave(&local_storage->lock, flags); 327 - if (likely(selem_linked_to_storage(selem))) 328 - free_local_storage = bpf_selem_unlink_storage_nolock( 329 - local_storage, selem, &selem_free_list); 330 - raw_spin_unlock_irqrestore(&local_storage->lock, flags); 331 - 332 - bpf_selem_free_list(&selem_free_list, reuse_now); 333 - 334 - if (free_local_storage) 335 - bpf_local_storage_free(local_storage, reuse_now); 336 - } 337 - 338 311 void bpf_selem_link_storage_nolock(struct bpf_local_storage *local_storage, 339 312 struct bpf_local_storage_elem *selem) 340 313 { ··· 359 386 hlist_add_head_rcu(&selem->map_node, &b->list); 360 387 } 361 388 362 - void bpf_selem_unlink(struct bpf_local_storage_elem *selem, bool reuse_now) 389 + int bpf_selem_unlink(struct bpf_local_storage_elem *selem, bool reuse_now) 363 390 { 364 - int err; 391 + struct bpf_local_storage *local_storage; 392 + bool free_local_storage = false; 393 + HLIST_HEAD(selem_free_list); 394 + unsigned long flags; 395 + int err = 0; 365 396 366 - /* Always unlink from map before unlinking from local_storage 367 - * because selem will be freed after successfully unlinked from 368 - * the local_storage. 369 - */ 370 - err = bpf_selem_unlink_map(selem); 371 - if (err) 372 - return; 397 + if (unlikely(!selem_linked_to_storage_lockless(selem))) 398 + /* selem has already been unlinked from sk */ 399 + return 0; 373 400 374 - bpf_selem_unlink_storage(selem, reuse_now); 401 + local_storage = rcu_dereference_check(selem->local_storage, 402 + bpf_rcu_lock_held()); 403 + 404 + raw_spin_lock_irqsave(&local_storage->lock, flags); 405 + if (likely(selem_linked_to_storage(selem))) { 406 + /* Always unlink from map before unlinking from local_storage 407 + * because selem will be freed after successfully unlinked from 408 + * the local_storage. 409 + */ 410 + err = bpf_selem_unlink_map(selem); 411 + if (err) 412 + goto out; 413 + 414 + free_local_storage = bpf_selem_unlink_storage_nolock( 415 + local_storage, selem, &selem_free_list); 416 + } 417 + out: 418 + raw_spin_unlock_irqrestore(&local_storage->lock, flags); 419 + 420 + bpf_selem_free_list(&selem_free_list, reuse_now); 421 + 422 + if (free_local_storage) 423 + bpf_local_storage_free(local_storage, reuse_now); 424 + 425 + return err; 375 426 } 376 427 377 428 void __bpf_local_storage_insert_cache(struct bpf_local_storage *local_storage,
+1 -3
kernel/bpf/bpf_task_storage.c
··· 167 167 if (!nobusy) 168 168 return -EBUSY; 169 169 170 - bpf_selem_unlink(SELEM(sdata), false); 171 - 172 - return 0; 170 + return bpf_selem_unlink(SELEM(sdata), false); 173 171 } 174 172 175 173 static long bpf_pid_task_storage_delete_elem(struct bpf_map *map, void *key)
+1 -3
net/core/bpf_sk_storage.c
··· 40 40 if (!sdata) 41 41 return -ENOENT; 42 42 43 - bpf_selem_unlink(SELEM(sdata), false); 44 - 45 - return 0; 43 + return bpf_selem_unlink(SELEM(sdata), false); 46 44 } 47 45 48 46 /* Called by __sk_destruct() & bpf_sk_storage_clone() */