kernel/bpf/reuseport_array.c

Source file repositories/reference/linux-study-clean/kernel/bpf/reuseport_array.c

File Facts

System
Linux kernel
Corpus path
kernel/bpf/reuseport_array.c
Extension
.c
Size
8801 bytes
Lines
354
Domain
Core OS
Bucket
Scheduler, Processes, Timers, Sync, And Syscalls
Inferred role
Core OS: implementation source
Status
source implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

struct reuseport_array {
	struct bpf_map map;
	struct sock __rcu *ptrs[];
};

static struct reuseport_array *reuseport_array(struct bpf_map *map)
{
	return (struct reuseport_array *)map;
}

/* The caller must hold the reuseport_lock */
void bpf_sk_reuseport_detach(struct sock *sk)
{
	struct sock __rcu **socks;

	write_lock_bh(&sk->sk_callback_lock);
	socks = __locked_read_sk_user_data_with_flags(sk, SK_USER_DATA_BPF);
	if (socks) {
		WRITE_ONCE(sk->sk_user_data, NULL);
		/*
		 * Do not move this NULL assignment outside of
		 * sk->sk_callback_lock because there is
		 * a race with reuseport_array_free()
		 * which does not hold the reuseport_lock.
		 */
		RCU_INIT_POINTER(*socks, NULL);
	}
	write_unlock_bh(&sk->sk_callback_lock);
}

static int reuseport_array_alloc_check(union bpf_attr *attr)
{
	if (attr->value_size != sizeof(u32) &&
	    attr->value_size != sizeof(u64))
		return -EINVAL;

	return array_map_alloc_check(attr);
}

static void *reuseport_array_lookup_elem(struct bpf_map *map, void *key)
{
	struct reuseport_array *array = reuseport_array(map);
	u32 index = *(u32 *)key;

	if (unlikely(index >= array->map.max_entries))
		return NULL;

	return rcu_dereference(array->ptrs[index]);
}

/* Called from syscall only */
static long reuseport_array_delete_elem(struct bpf_map *map, void *key)
{
	struct reuseport_array *array = reuseport_array(map);
	u32 index = *(u32 *)key;
	struct sock *sk;
	int err;

	if (index >= map->max_entries)
		return -E2BIG;

	if (!rcu_access_pointer(array->ptrs[index]))
		return -ENOENT;

	spin_lock_bh(&reuseport_lock);

	sk = rcu_dereference_protected(array->ptrs[index],
				       lockdep_is_held(&reuseport_lock));
	if (sk) {
		write_lock_bh(&sk->sk_callback_lock);
		WRITE_ONCE(sk->sk_user_data, NULL);
		RCU_INIT_POINTER(array->ptrs[index], NULL);
		write_unlock_bh(&sk->sk_callback_lock);
		err = 0;
	} else {
		err = -ENOENT;
	}

	spin_unlock_bh(&reuseport_lock);

	return err;
}

static void reuseport_array_free(struct bpf_map *map)
{
	struct reuseport_array *array = reuseport_array(map);
	struct sock *sk;
	u32 i;

	/*

Annotation

Implementation Notes