ee9fd0ac30
KCSAN reported a data-race when accessing node->ref. Although node->ref does not have to be accurate, take this chance to use a more common READ_ONCE() and WRITE_ONCE() pattern instead of data_race(). There is an existing bpf_lru_node_is_ref() and bpf_lru_node_set_ref(). This patch also adds bpf_lru_node_clear_ref() to do the WRITE_ONCE(node->ref, 0) also. ================================================================== BUG: KCSAN: data-race in __bpf_lru_list_rotate / __htab_lru_percpu_map_update_elem write to 0xffff888137038deb of 1 bytes by task 11240 on cpu 1: __bpf_lru_node_move kernel/bpf/bpf_lru_list.c:113 [inline] __bpf_lru_list_rotate_active kernel/bpf/bpf_lru_list.c:149 [inline] __bpf_lru_list_rotate+0x1bf/0x750 kernel/bpf/bpf_lru_list.c:240 bpf_lru_list_pop_free_to_local kernel/bpf/bpf_lru_list.c:329 [inline] bpf_common_lru_pop_free kernel/bpf/bpf_lru_list.c:447 [inline] bpf_lru_pop_free+0x638/0xe20 kernel/bpf/bpf_lru_list.c:499 prealloc_lru_pop kernel/bpf/hashtab.c:290 [inline] __htab_lru_percpu_map_update_elem+0xe7/0x820 kernel/bpf/hashtab.c:1316 bpf_percpu_hash_update+0x5e/0x90 kernel/bpf/hashtab.c:2313 bpf_map_update_value+0x2a9/0x370 kernel/bpf/syscall.c:200 generic_map_update_batch+0x3ae/0x4f0 kernel/bpf/syscall.c:1687 bpf_map_do_batch+0x2d9/0x3d0 kernel/bpf/syscall.c:4534 __sys_bpf+0x338/0x810 __do_sys_bpf kernel/bpf/syscall.c:5096 [inline] __se_sys_bpf kernel/bpf/syscall.c:5094 [inline] __x64_sys_bpf+0x43/0x50 kernel/bpf/syscall.c:5094 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x41/0xc0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd read to 0xffff888137038deb of 1 bytes by task 11241 on cpu 0: bpf_lru_node_set_ref kernel/bpf/bpf_lru_list.h:70 [inline] __htab_lru_percpu_map_update_elem+0x2f1/0x820 kernel/bpf/hashtab.c:1332 bpf_percpu_hash_update+0x5e/0x90 kernel/bpf/hashtab.c:2313 bpf_map_update_value+0x2a9/0x370 kernel/bpf/syscall.c:200 generic_map_update_batch+0x3ae/0x4f0 kernel/bpf/syscall.c:1687 bpf_map_do_batch+0x2d9/0x3d0 kernel/bpf/syscall.c:4534 __sys_bpf+0x338/0x810 __do_sys_bpf kernel/bpf/syscall.c:5096 [inline] __se_sys_bpf kernel/bpf/syscall.c:5094 [inline] __x64_sys_bpf+0x43/0x50 kernel/bpf/syscall.c:5094 do_syscall_x64 arch/x86/entry/common.c:50 [inline] do_syscall_64+0x41/0xc0 arch/x86/entry/common.c:80 entry_SYSCALL_64_after_hwframe+0x63/0xcd value changed: 0x01 -> 0x00 Reported by Kernel Concurrency Sanitizer on: CPU: 0 PID: 11241 Comm: syz-executor.3 Not tainted 6.3.0-rc7-syzkaller-00136-g6a66fdd29ea1 #0 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 03/30/2023 ================================================================== Reported-by: syzbot+ebe648a84e8784763f82@syzkaller.appspotmail.com Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org> Acked-by: Yonghong Song <yhs@fb.com> Link: https://lore.kernel.org/r/20230511043748.1384166-1-martin.lau@linux.dev Signed-off-by: Alexei Starovoitov <ast@kernel.org>
81 lines
2.0 KiB
C
81 lines
2.0 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/* Copyright (c) 2016 Facebook
|
|
*/
|
|
#ifndef __BPF_LRU_LIST_H_
|
|
#define __BPF_LRU_LIST_H_
|
|
|
|
#include <linux/cache.h>
|
|
#include <linux/list.h>
|
|
#include <linux/spinlock_types.h>
|
|
|
|
#define NR_BPF_LRU_LIST_T (3)
|
|
#define NR_BPF_LRU_LIST_COUNT (2)
|
|
#define NR_BPF_LRU_LOCAL_LIST_T (2)
|
|
#define BPF_LOCAL_LIST_T_OFFSET NR_BPF_LRU_LIST_T
|
|
|
|
enum bpf_lru_list_type {
|
|
BPF_LRU_LIST_T_ACTIVE,
|
|
BPF_LRU_LIST_T_INACTIVE,
|
|
BPF_LRU_LIST_T_FREE,
|
|
BPF_LRU_LOCAL_LIST_T_FREE,
|
|
BPF_LRU_LOCAL_LIST_T_PENDING,
|
|
};
|
|
|
|
struct bpf_lru_node {
|
|
struct list_head list;
|
|
u16 cpu;
|
|
u8 type;
|
|
u8 ref;
|
|
};
|
|
|
|
struct bpf_lru_list {
|
|
struct list_head lists[NR_BPF_LRU_LIST_T];
|
|
unsigned int counts[NR_BPF_LRU_LIST_COUNT];
|
|
/* The next inactive list rotation starts from here */
|
|
struct list_head *next_inactive_rotation;
|
|
|
|
raw_spinlock_t lock ____cacheline_aligned_in_smp;
|
|
};
|
|
|
|
struct bpf_lru_locallist {
|
|
struct list_head lists[NR_BPF_LRU_LOCAL_LIST_T];
|
|
u16 next_steal;
|
|
raw_spinlock_t lock;
|
|
};
|
|
|
|
struct bpf_common_lru {
|
|
struct bpf_lru_list lru_list;
|
|
struct bpf_lru_locallist __percpu *local_list;
|
|
};
|
|
|
|
typedef bool (*del_from_htab_func)(void *arg, struct bpf_lru_node *node);
|
|
|
|
struct bpf_lru {
|
|
union {
|
|
struct bpf_common_lru common_lru;
|
|
struct bpf_lru_list __percpu *percpu_lru;
|
|
};
|
|
del_from_htab_func del_from_htab;
|
|
void *del_arg;
|
|
unsigned int hash_offset;
|
|
unsigned int nr_scans;
|
|
bool percpu;
|
|
};
|
|
|
|
static inline void bpf_lru_node_set_ref(struct bpf_lru_node *node)
|
|
{
|
|
if (!READ_ONCE(node->ref))
|
|
WRITE_ONCE(node->ref, 1);
|
|
}
|
|
|
|
int bpf_lru_init(struct bpf_lru *lru, bool percpu, u32 hash_offset,
|
|
del_from_htab_func del_from_htab, void *delete_arg);
|
|
void bpf_lru_populate(struct bpf_lru *lru, void *buf, u32 node_offset,
|
|
u32 elem_size, u32 nr_elems);
|
|
void bpf_lru_destroy(struct bpf_lru *lru);
|
|
struct bpf_lru_node *bpf_lru_pop_free(struct bpf_lru *lru, u32 hash);
|
|
void bpf_lru_push_free(struct bpf_lru *lru, struct bpf_lru_node *node);
|
|
void bpf_lru_promote(struct bpf_lru *lru, struct bpf_lru_node *node);
|
|
|
|
#endif
|