Contributors: 3
Author Tokens Token Proportion Commits Commit Proportion
Kumar Kartikeya Dwivedi 1793 94.32% 1 16.67%
Dave Marchevsky 77 4.05% 2 33.33%
Alexei Starovoitov 31 1.63% 3 50.00%
Total 1901 6

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
// SPDX-License-Identifier: GPL-2.0
#include <vmlinux.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_core_read.h>
#include "bpf_experimental.h"

#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (int)(sizeof(x) / sizeof((x)[0]))
#endif

#include "linked_list.h"

static __always_inline
int list_push_pop(struct bpf_spin_lock *lock, struct bpf_list_head *head, bool leave_in_map)
{
	struct bpf_list_node *n;
	struct foo *f;

	f = bpf_obj_new(typeof(*f));
	if (!f)
		return 2;

	bpf_spin_lock(lock);
	n = bpf_list_pop_front(head);
	bpf_spin_unlock(lock);
	if (n) {
		bpf_obj_drop(container_of(n, struct foo, node2));
		bpf_obj_drop(f);
		return 3;
	}

	bpf_spin_lock(lock);
	n = bpf_list_pop_back(head);
	bpf_spin_unlock(lock);
	if (n) {
		bpf_obj_drop(container_of(n, struct foo, node2));
		bpf_obj_drop(f);
		return 4;
	}


	bpf_spin_lock(lock);
	f->data = 42;
	bpf_list_push_front(head, &f->node2);
	bpf_spin_unlock(lock);
	if (leave_in_map)
		return 0;
	bpf_spin_lock(lock);
	n = bpf_list_pop_back(head);
	bpf_spin_unlock(lock);
	if (!n)
		return 5;
	f = container_of(n, struct foo, node2);
	if (f->data != 42) {
		bpf_obj_drop(f);
		return 6;
	}

	bpf_spin_lock(lock);
	f->data = 13;
	bpf_list_push_front(head, &f->node2);
	bpf_spin_unlock(lock);
	bpf_spin_lock(lock);
	n = bpf_list_pop_front(head);
	bpf_spin_unlock(lock);
	if (!n)
		return 7;
	f = container_of(n, struct foo, node2);
	if (f->data != 13) {
		bpf_obj_drop(f);
		return 8;
	}
	bpf_obj_drop(f);

	bpf_spin_lock(lock);
	n = bpf_list_pop_front(head);
	bpf_spin_unlock(lock);
	if (n) {
		bpf_obj_drop(container_of(n, struct foo, node2));
		return 9;
	}

	bpf_spin_lock(lock);
	n = bpf_list_pop_back(head);
	bpf_spin_unlock(lock);
	if (n) {
		bpf_obj_drop(container_of(n, struct foo, node2));
		return 10;
	}
	return 0;
}


static __always_inline
int list_push_pop_multiple(struct bpf_spin_lock *lock, struct bpf_list_head *head, bool leave_in_map)
{
	struct bpf_list_node *n;
	struct foo *f[200], *pf;
	int i;

	/* Loop following this check adds nodes 2-at-a-time in order to
	 * validate multiple release_on_unlock release logic
	 */
	if (ARRAY_SIZE(f) % 2)
		return 10;

	for (i = 0; i < ARRAY_SIZE(f); i += 2) {
		f[i] = bpf_obj_new(typeof(**f));
		if (!f[i])
			return 2;
		f[i]->data = i;

		f[i + 1] = bpf_obj_new(typeof(**f));
		if (!f[i + 1]) {
			bpf_obj_drop(f[i]);
			return 9;
		}
		f[i + 1]->data = i + 1;

		bpf_spin_lock(lock);
		bpf_list_push_front(head, &f[i]->node2);
		bpf_list_push_front(head, &f[i + 1]->node2);
		bpf_spin_unlock(lock);
	}

	for (i = 0; i < ARRAY_SIZE(f); i++) {
		bpf_spin_lock(lock);
		n = bpf_list_pop_front(head);
		bpf_spin_unlock(lock);
		if (!n)
			return 3;
		pf = container_of(n, struct foo, node2);
		if (pf->data != (ARRAY_SIZE(f) - i - 1)) {
			bpf_obj_drop(pf);
			return 4;
		}
		bpf_spin_lock(lock);
		bpf_list_push_back(head, &pf->node2);
		bpf_spin_unlock(lock);
	}

	if (leave_in_map)
		return 0;

	for (i = 0; i < ARRAY_SIZE(f); i++) {
		bpf_spin_lock(lock);
		n = bpf_list_pop_back(head);
		bpf_spin_unlock(lock);
		if (!n)
			return 5;
		pf = container_of(n, struct foo, node2);
		if (pf->data != i) {
			bpf_obj_drop(pf);
			return 6;
		}
		bpf_obj_drop(pf);
	}
	bpf_spin_lock(lock);
	n = bpf_list_pop_back(head);
	bpf_spin_unlock(lock);
	if (n) {
		bpf_obj_drop(container_of(n, struct foo, node2));
		return 7;
	}

	bpf_spin_lock(lock);
	n = bpf_list_pop_front(head);
	bpf_spin_unlock(lock);
	if (n) {
		bpf_obj_drop(container_of(n, struct foo, node2));
		return 8;
	}
	return 0;
}

static __always_inline
int list_in_list(struct bpf_spin_lock *lock, struct bpf_list_head *head, bool leave_in_map)
{
	struct bpf_list_node *n;
	struct bar *ba[8], *b;
	struct foo *f;
	int i;

	f = bpf_obj_new(typeof(*f));
	if (!f)
		return 2;
	for (i = 0; i < ARRAY_SIZE(ba); i++) {
		b = bpf_obj_new(typeof(*b));
		if (!b) {
			bpf_obj_drop(f);
			return 3;
		}
		b->data = i;
		bpf_spin_lock(&f->lock);
		bpf_list_push_back(&f->head, &b->node);
		bpf_spin_unlock(&f->lock);
	}

	bpf_spin_lock(lock);
	f->data = 42;
	bpf_list_push_front(head, &f->node2);
	bpf_spin_unlock(lock);

	if (leave_in_map)
		return 0;

	bpf_spin_lock(lock);
	n = bpf_list_pop_front(head);
	bpf_spin_unlock(lock);
	if (!n)
		return 4;
	f = container_of(n, struct foo, node2);
	if (f->data != 42) {
		bpf_obj_drop(f);
		return 5;
	}

	for (i = 0; i < ARRAY_SIZE(ba); i++) {
		bpf_spin_lock(&f->lock);
		n = bpf_list_pop_front(&f->head);
		bpf_spin_unlock(&f->lock);
		if (!n) {
			bpf_obj_drop(f);
			return 6;
		}
		b = container_of(n, struct bar, node);
		if (b->data != i) {
			bpf_obj_drop(f);
			bpf_obj_drop(b);
			return 7;
		}
		bpf_obj_drop(b);
	}
	bpf_spin_lock(&f->lock);
	n = bpf_list_pop_front(&f->head);
	bpf_spin_unlock(&f->lock);
	if (n) {
		bpf_obj_drop(f);
		bpf_obj_drop(container_of(n, struct bar, node));
		return 8;
	}
	bpf_obj_drop(f);
	return 0;
}

static __always_inline
int test_list_push_pop(struct bpf_spin_lock *lock, struct bpf_list_head *head)
{
	int ret;

	ret = list_push_pop(lock, head, false);
	if (ret)
		return ret;
	return list_push_pop(lock, head, true);
}

static __always_inline
int test_list_push_pop_multiple(struct bpf_spin_lock *lock, struct bpf_list_head *head)
{
	int ret;

	ret = list_push_pop_multiple(lock, head, false);
	if (ret)
		return ret;
	return list_push_pop_multiple(lock, head, true);
}

static __always_inline
int test_list_in_list(struct bpf_spin_lock *lock, struct bpf_list_head *head)
{
	int ret;

	ret = list_in_list(lock, head, false);
	if (ret)
		return ret;
	return list_in_list(lock, head, true);
}

SEC("tc")
int map_list_push_pop(void *ctx)
{
	struct map_value *v;

	v = bpf_map_lookup_elem(&array_map, &(int){0});
	if (!v)
		return 1;
	return test_list_push_pop(&v->lock, &v->head);
}

SEC("tc")
int inner_map_list_push_pop(void *ctx)
{
	struct map_value *v;
	void *map;

	map = bpf_map_lookup_elem(&map_of_maps, &(int){0});
	if (!map)
		return 1;
	v = bpf_map_lookup_elem(map, &(int){0});
	if (!v)
		return 1;
	return test_list_push_pop(&v->lock, &v->head);
}

SEC("tc")
int global_list_push_pop(void *ctx)
{
	return test_list_push_pop(&glock, &ghead);
}

SEC("tc")
int map_list_push_pop_multiple(void *ctx)
{
	struct map_value *v;

	v = bpf_map_lookup_elem(&array_map, &(int){0});
	if (!v)
		return 1;
	return test_list_push_pop_multiple(&v->lock, &v->head);
}

SEC("tc")
int inner_map_list_push_pop_multiple(void *ctx)
{
	struct map_value *v;
	void *map;

	map = bpf_map_lookup_elem(&map_of_maps, &(int){0});
	if (!map)
		return 1;
	v = bpf_map_lookup_elem(map, &(int){0});
	if (!v)
		return 1;
	return test_list_push_pop_multiple(&v->lock, &v->head);
}

SEC("tc")
int global_list_push_pop_multiple(void *ctx)
{
	int ret;

	ret = list_push_pop_multiple(&glock, &ghead, false);
	if (ret)
		return ret;
	return list_push_pop_multiple(&glock, &ghead, true);
}

SEC("tc")
int map_list_in_list(void *ctx)
{
	struct map_value *v;

	v = bpf_map_lookup_elem(&array_map, &(int){0});
	if (!v)
		return 1;
	return test_list_in_list(&v->lock, &v->head);
}

SEC("tc")
int inner_map_list_in_list(void *ctx)
{
	struct map_value *v;
	void *map;

	map = bpf_map_lookup_elem(&map_of_maps, &(int){0});
	if (!map)
		return 1;
	v = bpf_map_lookup_elem(map, &(int){0});
	if (!v)
		return 1;
	return test_list_in_list(&v->lock, &v->head);
}

SEC("tc")
int global_list_in_list(void *ctx)
{
	return test_list_in_list(&glock, &ghead);
}

char _license[] SEC("license") = "GPL";