Commit fc22d949 authored by Benjamin Tissoires's avatar Benjamin Tissoires Committed by Alexei Starovoitov

bpf: replace bpf_timer_cancel_and_free with a generic helper

Same reason than most bpf_timer* functions, we need almost the same for
workqueues.
So extract the generic part out of it so bpf_wq_cancel_and_free can reuse
it.
Signed-off-by: default avatarBenjamin Tissoires <bentiss@kernel.org>
Link: https://lore.kernel.org/r/20240420-bpf_wq-v2-4-6c986a5a741f@kernel.orgSigned-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parent 073f11b0
...@@ -1413,36 +1413,44 @@ static const struct bpf_func_proto bpf_timer_cancel_proto = { ...@@ -1413,36 +1413,44 @@ static const struct bpf_func_proto bpf_timer_cancel_proto = {
.arg1_type = ARG_PTR_TO_TIMER, .arg1_type = ARG_PTR_TO_TIMER,
}; };
/* This function is called by map_delete/update_elem for individual element and static struct bpf_async_cb *__bpf_async_cancel_and_free(struct bpf_async_kern *async)
* by ops->map_release_uref when the user space reference to a map reaches zero.
*/
void bpf_timer_cancel_and_free(void *val)
{ {
struct bpf_async_kern *timer = val; struct bpf_async_cb *cb;
struct bpf_hrtimer *t;
/* Performance optimization: read timer->timer without lock first. */ /* Performance optimization: read async->cb without lock first. */
if (!READ_ONCE(timer->timer)) if (!READ_ONCE(async->cb))
return; return NULL;
__bpf_spin_lock_irqsave(&timer->lock); __bpf_spin_lock_irqsave(&async->lock);
/* re-read it under lock */ /* re-read it under lock */
t = timer->timer; cb = async->cb;
if (!t) if (!cb)
goto out; goto out;
drop_prog_refcnt(&t->cb); drop_prog_refcnt(cb);
/* The subsequent bpf_timer_start/cancel() helpers won't be able to use /* The subsequent bpf_timer_start/cancel() helpers won't be able to use
* this timer, since it won't be initialized. * this timer, since it won't be initialized.
*/ */
WRITE_ONCE(timer->timer, NULL); WRITE_ONCE(async->cb, NULL);
out: out:
__bpf_spin_unlock_irqrestore(&timer->lock); __bpf_spin_unlock_irqrestore(&async->lock);
return cb;
}
/* This function is called by map_delete/update_elem for individual element and
* by ops->map_release_uref when the user space reference to a map reaches zero.
*/
void bpf_timer_cancel_and_free(void *val)
{
struct bpf_hrtimer *t;
t = (struct bpf_hrtimer *)__bpf_async_cancel_and_free(val);
if (!t) if (!t)
return; return;
/* Cancel the timer and wait for callback to complete if it was running. /* Cancel the timer and wait for callback to complete if it was running.
* If hrtimer_cancel() can be safely called it's safe to call kfree(t) * If hrtimer_cancel() can be safely called it's safe to call kfree(t)
* right after for both preallocated and non-preallocated maps. * right after for both preallocated and non-preallocated maps.
* The timer->timer = NULL was already done and no code path can * The async->cb = NULL was already done and no code path can
* see address 't' anymore. * see address 't' anymore.
* *
* Check that bpf_map_delete/update_elem() wasn't called from timer * Check that bpf_map_delete/update_elem() wasn't called from timer
...@@ -1451,7 +1459,7 @@ void bpf_timer_cancel_and_free(void *val) ...@@ -1451,7 +1459,7 @@ void bpf_timer_cancel_and_free(void *val)
* return -1). Though callback_fn is still running on this cpu it's * return -1). Though callback_fn is still running on this cpu it's
* safe to do kfree(t) because bpf_timer_cb() read everything it needed * safe to do kfree(t) because bpf_timer_cb() read everything it needed
* from 't'. The bpf subprog callback_fn won't be able to access 't', * from 't'. The bpf subprog callback_fn won't be able to access 't',
* since timer->timer = NULL was already done. The timer will be * since async->cb = NULL was already done. The timer will be
* effectively cancelled because bpf_timer_cb() will return * effectively cancelled because bpf_timer_cb() will return
* HRTIMER_NORESTART. * HRTIMER_NORESTART.
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment