Skip to content

Commit c83597f

Browse files
yonghong-songAlexei Starovoitov
authored andcommitted
bpf: Refactor some inode/task/sk storage functions for reuse
Refactor codes so that inode/task/sk storage implementation can maximally share the same code. I also added some comments in new function bpf_local_storage_unlink_nolock() to make codes easy to understand. There is no functionality change. Acked-by: David Vernet <[email protected]> Signed-off-by: Yonghong Song <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 5e67b8e commit c83597f

File tree

5 files changed

+137
-181
lines changed

5 files changed

+137
-181
lines changed

include/linux/bpf_local_storage.h

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -116,21 +116,22 @@ static struct bpf_local_storage_cache name = { \
116116
.idx_lock = __SPIN_LOCK_UNLOCKED(name.idx_lock), \
117117
}
118118

119-
u16 bpf_local_storage_cache_idx_get(struct bpf_local_storage_cache *cache);
120-
void bpf_local_storage_cache_idx_free(struct bpf_local_storage_cache *cache,
121-
u16 idx);
122-
123119
/* Helper functions for bpf_local_storage */
124120
int bpf_local_storage_map_alloc_check(union bpf_attr *attr);
125121

126-
struct bpf_local_storage_map *bpf_local_storage_map_alloc(union bpf_attr *attr);
122+
struct bpf_map *
123+
bpf_local_storage_map_alloc(union bpf_attr *attr,
124+
struct bpf_local_storage_cache *cache);
127125

128126
struct bpf_local_storage_data *
129127
bpf_local_storage_lookup(struct bpf_local_storage *local_storage,
130128
struct bpf_local_storage_map *smap,
131129
bool cacheit_lockit);
132130

133-
void bpf_local_storage_map_free(struct bpf_local_storage_map *smap,
131+
bool bpf_local_storage_unlink_nolock(struct bpf_local_storage *local_storage);
132+
133+
void bpf_local_storage_map_free(struct bpf_map *map,
134+
struct bpf_local_storage_cache *cache,
134135
int __percpu *busy_counter);
135136

136137
int bpf_local_storage_map_check_btf(const struct bpf_map *map,
@@ -141,10 +142,6 @@ int bpf_local_storage_map_check_btf(const struct bpf_map *map,
141142
void bpf_selem_link_storage_nolock(struct bpf_local_storage *local_storage,
142143
struct bpf_local_storage_elem *selem);
143144

144-
bool bpf_selem_unlink_storage_nolock(struct bpf_local_storage *local_storage,
145-
struct bpf_local_storage_elem *selem,
146-
bool uncharge_omem, bool use_trace_rcu);
147-
148145
void bpf_selem_unlink(struct bpf_local_storage_elem *selem, bool use_trace_rcu);
149146

150147
void bpf_selem_link_map(struct bpf_local_storage_map *smap,

kernel/bpf/bpf_inode_storage.c

Lines changed: 3 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,9 @@ static struct bpf_local_storage_data *inode_storage_lookup(struct inode *inode,
5656

5757
void bpf_inode_storage_free(struct inode *inode)
5858
{
59-
struct bpf_local_storage_elem *selem;
6059
struct bpf_local_storage *local_storage;
6160
bool free_inode_storage = false;
6261
struct bpf_storage_blob *bsb;
63-
struct hlist_node *n;
6462

6563
bsb = bpf_inode(inode);
6664
if (!bsb)
@@ -74,30 +72,11 @@ void bpf_inode_storage_free(struct inode *inode)
7472
return;
7573
}
7674

77-
/* Neither the bpf_prog nor the bpf-map's syscall
78-
* could be modifying the local_storage->list now.
79-
* Thus, no elem can be added-to or deleted-from the
80-
* local_storage->list by the bpf_prog or by the bpf-map's syscall.
81-
*
82-
* It is racing with bpf_local_storage_map_free() alone
83-
* when unlinking elem from the local_storage->list and
84-
* the map's bucket->list.
85-
*/
8675
raw_spin_lock_bh(&local_storage->lock);
87-
hlist_for_each_entry_safe(selem, n, &local_storage->list, snode) {
88-
/* Always unlink from map before unlinking from
89-
* local_storage.
90-
*/
91-
bpf_selem_unlink_map(selem);
92-
free_inode_storage = bpf_selem_unlink_storage_nolock(
93-
local_storage, selem, false, false);
94-
}
76+
free_inode_storage = bpf_local_storage_unlink_nolock(local_storage);
9577
raw_spin_unlock_bh(&local_storage->lock);
9678
rcu_read_unlock();
9779

98-
/* free_inoode_storage should always be true as long as
99-
* local_storage->list was non-empty.
100-
*/
10180
if (free_inode_storage)
10281
kfree_rcu(local_storage, rcu);
10382
}
@@ -226,23 +205,12 @@ static int notsupp_get_next_key(struct bpf_map *map, void *key,
226205

227206
static struct bpf_map *inode_storage_map_alloc(union bpf_attr *attr)
228207
{
229-
struct bpf_local_storage_map *smap;
230-
231-
smap = bpf_local_storage_map_alloc(attr);
232-
if (IS_ERR(smap))
233-
return ERR_CAST(smap);
234-
235-
smap->cache_idx = bpf_local_storage_cache_idx_get(&inode_cache);
236-
return &smap->map;
208+
return bpf_local_storage_map_alloc(attr, &inode_cache);
237209
}
238210

239211
static void inode_storage_map_free(struct bpf_map *map)
240212
{
241-
struct bpf_local_storage_map *smap;
242-
243-
smap = (struct bpf_local_storage_map *)map;
244-
bpf_local_storage_cache_idx_free(&inode_cache, smap->cache_idx);
245-
bpf_local_storage_map_free(smap, NULL);
213+
bpf_local_storage_map_free(map, &inode_cache, NULL);
246214
}
247215

248216
BTF_ID_LIST_SINGLE(inode_storage_map_btf_ids, struct,

kernel/bpf/bpf_local_storage.c

Lines changed: 121 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,9 @@ static void bpf_selem_free_rcu(struct rcu_head *rcu)
113113
* The caller must ensure selem->smap is still valid to be
114114
* dereferenced for its smap->elem_size and smap->cache_idx.
115115
*/
116-
bool bpf_selem_unlink_storage_nolock(struct bpf_local_storage *local_storage,
117-
struct bpf_local_storage_elem *selem,
118-
bool uncharge_mem, bool use_trace_rcu)
116+
static bool bpf_selem_unlink_storage_nolock(struct bpf_local_storage *local_storage,
117+
struct bpf_local_storage_elem *selem,
118+
bool uncharge_mem, bool use_trace_rcu)
119119
{
120120
struct bpf_local_storage_map *smap;
121121
bool free_local_storage;
@@ -501,7 +501,7 @@ bpf_local_storage_update(void *owner, struct bpf_local_storage_map *smap,
501501
return ERR_PTR(err);
502502
}
503503

504-
u16 bpf_local_storage_cache_idx_get(struct bpf_local_storage_cache *cache)
504+
static u16 bpf_local_storage_cache_idx_get(struct bpf_local_storage_cache *cache)
505505
{
506506
u64 min_usage = U64_MAX;
507507
u16 i, res = 0;
@@ -525,76 +525,14 @@ u16 bpf_local_storage_cache_idx_get(struct bpf_local_storage_cache *cache)
525525
return res;
526526
}
527527

528-
void bpf_local_storage_cache_idx_free(struct bpf_local_storage_cache *cache,
529-
u16 idx)
528+
static void bpf_local_storage_cache_idx_free(struct bpf_local_storage_cache *cache,
529+
u16 idx)
530530
{
531531
spin_lock(&cache->idx_lock);
532532
cache->idx_usage_counts[idx]--;
533533
spin_unlock(&cache->idx_lock);
534534
}
535535

536-
void bpf_local_storage_map_free(struct bpf_local_storage_map *smap,
537-
int __percpu *busy_counter)
538-
{
539-
struct bpf_local_storage_elem *selem;
540-
struct bpf_local_storage_map_bucket *b;
541-
unsigned int i;
542-
543-
/* Note that this map might be concurrently cloned from
544-
* bpf_sk_storage_clone. Wait for any existing bpf_sk_storage_clone
545-
* RCU read section to finish before proceeding. New RCU
546-
* read sections should be prevented via bpf_map_inc_not_zero.
547-
*/
548-
synchronize_rcu();
549-
550-
/* bpf prog and the userspace can no longer access this map
551-
* now. No new selem (of this map) can be added
552-
* to the owner->storage or to the map bucket's list.
553-
*
554-
* The elem of this map can be cleaned up here
555-
* or when the storage is freed e.g.
556-
* by bpf_sk_storage_free() during __sk_destruct().
557-
*/
558-
for (i = 0; i < (1U << smap->bucket_log); i++) {
559-
b = &smap->buckets[i];
560-
561-
rcu_read_lock();
562-
/* No one is adding to b->list now */
563-
while ((selem = hlist_entry_safe(
564-
rcu_dereference_raw(hlist_first_rcu(&b->list)),
565-
struct bpf_local_storage_elem, map_node))) {
566-
if (busy_counter) {
567-
migrate_disable();
568-
this_cpu_inc(*busy_counter);
569-
}
570-
bpf_selem_unlink(selem, false);
571-
if (busy_counter) {
572-
this_cpu_dec(*busy_counter);
573-
migrate_enable();
574-
}
575-
cond_resched_rcu();
576-
}
577-
rcu_read_unlock();
578-
}
579-
580-
/* While freeing the storage we may still need to access the map.
581-
*
582-
* e.g. when bpf_sk_storage_free() has unlinked selem from the map
583-
* which then made the above while((selem = ...)) loop
584-
* exit immediately.
585-
*
586-
* However, while freeing the storage one still needs to access the
587-
* smap->elem_size to do the uncharging in
588-
* bpf_selem_unlink_storage_nolock().
589-
*
590-
* Hence, wait another rcu grace period for the storage to be freed.
591-
*/
592-
synchronize_rcu();
593-
594-
kvfree(smap->buckets);
595-
bpf_map_area_free(smap);
596-
}
597-
598536
int bpf_local_storage_map_alloc_check(union bpf_attr *attr)
599537
{
600538
if (attr->map_flags & ~BPF_LOCAL_STORAGE_CREATE_FLAG_MASK ||
@@ -614,7 +552,7 @@ int bpf_local_storage_map_alloc_check(union bpf_attr *attr)
614552
return 0;
615553
}
616554

617-
struct bpf_local_storage_map *bpf_local_storage_map_alloc(union bpf_attr *attr)
555+
static struct bpf_local_storage_map *__bpf_local_storage_map_alloc(union bpf_attr *attr)
618556
{
619557
struct bpf_local_storage_map *smap;
620558
unsigned int i;
@@ -664,3 +602,117 @@ int bpf_local_storage_map_check_btf(const struct bpf_map *map,
664602

665603
return 0;
666604
}
605+
606+
bool bpf_local_storage_unlink_nolock(struct bpf_local_storage *local_storage)
607+
{
608+
struct bpf_local_storage_elem *selem;
609+
bool free_storage = false;
610+
struct hlist_node *n;
611+
612+
/* Neither the bpf_prog nor the bpf_map's syscall
613+
* could be modifying the local_storage->list now.
614+
* Thus, no elem can be added to or deleted from the
615+
* local_storage->list by the bpf_prog or by the bpf_map's syscall.
616+
*
617+
* It is racing with bpf_local_storage_map_free() alone
618+
* when unlinking elem from the local_storage->list and
619+
* the map's bucket->list.
620+
*/
621+
hlist_for_each_entry_safe(selem, n, &local_storage->list, snode) {
622+
/* Always unlink from map before unlinking from
623+
* local_storage.
624+
*/
625+
bpf_selem_unlink_map(selem);
626+
/* If local_storage list has only one element, the
627+
* bpf_selem_unlink_storage_nolock() will return true.
628+
* Otherwise, it will return false. The current loop iteration
629+
* intends to remove all local storage. So the last iteration
630+
* of the loop will set the free_cgroup_storage to true.
631+
*/
632+
free_storage = bpf_selem_unlink_storage_nolock(
633+
local_storage, selem, false, false);
634+
}
635+
636+
return free_storage;
637+
}
638+
639+
struct bpf_map *
640+
bpf_local_storage_map_alloc(union bpf_attr *attr,
641+
struct bpf_local_storage_cache *cache)
642+
{
643+
struct bpf_local_storage_map *smap;
644+
645+
smap = __bpf_local_storage_map_alloc(attr);
646+
if (IS_ERR(smap))
647+
return ERR_CAST(smap);
648+
649+
smap->cache_idx = bpf_local_storage_cache_idx_get(cache);
650+
return &smap->map;
651+
}
652+
653+
void bpf_local_storage_map_free(struct bpf_map *map,
654+
struct bpf_local_storage_cache *cache,
655+
int __percpu *busy_counter)
656+
{
657+
struct bpf_local_storage_map_bucket *b;
658+
struct bpf_local_storage_elem *selem;
659+
struct bpf_local_storage_map *smap;
660+
unsigned int i;
661+
662+
smap = (struct bpf_local_storage_map *)map;
663+
bpf_local_storage_cache_idx_free(cache, smap->cache_idx);
664+
665+
/* Note that this map might be concurrently cloned from
666+
* bpf_sk_storage_clone. Wait for any existing bpf_sk_storage_clone
667+
* RCU read section to finish before proceeding. New RCU
668+
* read sections should be prevented via bpf_map_inc_not_zero.
669+
*/
670+
synchronize_rcu();
671+
672+
/* bpf prog and the userspace can no longer access this map
673+
* now. No new selem (of this map) can be added
674+
* to the owner->storage or to the map bucket's list.
675+
*
676+
* The elem of this map can be cleaned up here
677+
* or when the storage is freed e.g.
678+
* by bpf_sk_storage_free() during __sk_destruct().
679+
*/
680+
for (i = 0; i < (1U << smap->bucket_log); i++) {
681+
b = &smap->buckets[i];
682+
683+
rcu_read_lock();
684+
/* No one is adding to b->list now */
685+
while ((selem = hlist_entry_safe(
686+
rcu_dereference_raw(hlist_first_rcu(&b->list)),
687+
struct bpf_local_storage_elem, map_node))) {
688+
if (busy_counter) {
689+
migrate_disable();
690+
this_cpu_inc(*busy_counter);
691+
}
692+
bpf_selem_unlink(selem, false);
693+
if (busy_counter) {
694+
this_cpu_dec(*busy_counter);
695+
migrate_enable();
696+
}
697+
cond_resched_rcu();
698+
}
699+
rcu_read_unlock();
700+
}
701+
702+
/* While freeing the storage we may still need to access the map.
703+
*
704+
* e.g. when bpf_sk_storage_free() has unlinked selem from the map
705+
* which then made the above while((selem = ...)) loop
706+
* exit immediately.
707+
*
708+
* However, while freeing the storage one still needs to access the
709+
* smap->elem_size to do the uncharging in
710+
* bpf_selem_unlink_storage_nolock().
711+
*
712+
* Hence, wait another rcu grace period for the storage to be freed.
713+
*/
714+
synchronize_rcu();
715+
716+
kvfree(smap->buckets);
717+
bpf_map_area_free(smap);
718+
}

0 commit comments

Comments
 (0)