Commit 403e935f authored by Amery Hung's avatar Amery Hung Committed by Martin KaFai Lau
Browse files

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: default avatarAlexei Starovoitov <ast@kernel.org>
Signed-off-by: default avatarAmery Hung <ameryhung@gmail.com>
Signed-off-by: default avatarMartin KaFai Lau <martin.lau@kernel.org>
Link: https://patch.msgid.link/20260205222916.1788211-5-ameryhung@gmail.com
parent fd103ffc
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -176,7 +176,7 @@ int bpf_local_storage_map_check_btf(const struct bpf_map *map,
void bpf_selem_link_storage_nolock(struct bpf_local_storage *local_storage,
				   struct bpf_local_storage_elem *selem);

void bpf_selem_unlink(struct bpf_local_storage_elem *selem, bool reuse_now);
int bpf_selem_unlink(struct bpf_local_storage_elem *selem, bool reuse_now);

int bpf_selem_link_map(struct bpf_local_storage_map *smap,
		       struct bpf_local_storage *local_storage,
+1 −2
Original line number Diff line number Diff line
@@ -118,8 +118,7 @@ static int cgroup_storage_delete(struct cgroup *cgroup, struct bpf_map *map)
	if (!sdata)
		return -ENOENT;

	bpf_selem_unlink(SELEM(sdata), false);
	return 0;
	return bpf_selem_unlink(SELEM(sdata), false);
}

static long bpf_cgrp_storage_delete_elem(struct bpf_map *map, void *key)
+1 −3
Original line number Diff line number Diff line
@@ -110,9 +110,7 @@ static int inode_storage_delete(struct inode *inode, struct bpf_map *map)
	if (!sdata)
		return -ENOENT;

	bpf_selem_unlink(SELEM(sdata), false);

	return 0;
	return bpf_selem_unlink(SELEM(sdata), false);
}

static long bpf_fd_inode_storage_delete_elem(struct bpf_map *map, void *key)
+34 −37
Original line number Diff line number Diff line
@@ -308,33 +308,6 @@ static bool bpf_selem_unlink_storage_nolock(struct bpf_local_storage *local_stor
	return free_local_storage;
}

static void bpf_selem_unlink_storage(struct bpf_local_storage_elem *selem,
				     bool reuse_now)
{
	struct bpf_local_storage *local_storage;
	bool free_local_storage = false;
	HLIST_HEAD(selem_free_list);
	unsigned long flags;

	if (unlikely(!selem_linked_to_storage_lockless(selem)))
		/* selem has already been unlinked from sk */
		return;

	local_storage = rcu_dereference_check(selem->local_storage,
					      bpf_rcu_lock_held());

	raw_spin_lock_irqsave(&local_storage->lock, flags);
	if (likely(selem_linked_to_storage(selem)))
		free_local_storage = bpf_selem_unlink_storage_nolock(
			local_storage, selem, &selem_free_list);
	raw_spin_unlock_irqrestore(&local_storage->lock, flags);

	bpf_selem_free_list(&selem_free_list, reuse_now);

	if (free_local_storage)
		bpf_local_storage_free(local_storage, reuse_now);
}

void bpf_selem_link_storage_nolock(struct bpf_local_storage *local_storage,
				   struct bpf_local_storage_elem *selem)
{
@@ -386,19 +359,43 @@ static void bpf_selem_link_map_nolock(struct bpf_local_storage_map_bucket *b,
	hlist_add_head_rcu(&selem->map_node, &b->list);
}

void bpf_selem_unlink(struct bpf_local_storage_elem *selem, bool reuse_now)
int bpf_selem_unlink(struct bpf_local_storage_elem *selem, bool reuse_now)
{
	int err;
	struct bpf_local_storage *local_storage;
	bool free_local_storage = false;
	HLIST_HEAD(selem_free_list);
	unsigned long flags;
	int err = 0;

	if (unlikely(!selem_linked_to_storage_lockless(selem)))
		/* selem has already been unlinked from sk */
		return 0;

	local_storage = rcu_dereference_check(selem->local_storage,
					      bpf_rcu_lock_held());

	raw_spin_lock_irqsave(&local_storage->lock, flags);
	if (likely(selem_linked_to_storage(selem))) {
		/* Always unlink from map before unlinking from local_storage
		 * because selem will be freed after successfully unlinked from
		 * the local_storage.
		 */
		err = bpf_selem_unlink_map(selem);
		if (err)
		return;
			goto out;

		free_local_storage = bpf_selem_unlink_storage_nolock(
			local_storage, selem, &selem_free_list);
	}
out:
	raw_spin_unlock_irqrestore(&local_storage->lock, flags);

	bpf_selem_unlink_storage(selem, reuse_now);
	bpf_selem_free_list(&selem_free_list, reuse_now);

	if (free_local_storage)
		bpf_local_storage_free(local_storage, reuse_now);

	return err;
}

void __bpf_local_storage_insert_cache(struct bpf_local_storage *local_storage,
+1 −3
Original line number Diff line number Diff line
@@ -167,9 +167,7 @@ static int task_storage_delete(struct task_struct *task, struct bpf_map *map,
	if (!nobusy)
		return -EBUSY;

	bpf_selem_unlink(SELEM(sdata), false);

	return 0;
	return bpf_selem_unlink(SELEM(sdata), false);
}

static long bpf_pid_task_storage_delete_elem(struct bpf_map *map, void *key)
Loading