Skip to content

Commit b23bfa5

Browse files
jrfastabborkmann
authored andcommitted
bpf, xdp: Remove no longer required rcu_read_{un}lock()
Now that we depend on rcu_call() and synchronize_rcu() to also wait for preempt_disabled region to complete the rcu read critical section in __dev_map_flush() is no longer required. Except in a few special cases in drivers that need it for other reasons. These originally ensured the map reference was safe while a map was also being free'd. And additionally that bpf program updates via ndo_bpf did not happen while flush updates were in flight. But flush by new rules can only be called from preempt-disabled NAPI context. The synchronize_rcu from the map free path and the rcu_call from the delete path will ensure the reference there is safe. So lets remove the rcu_read_lock and rcu_read_unlock pair to avoid any confusion around how this is being protected. If the rcu_read_lock was required it would mean errors in the above logic and the original patch would also be wrong. Now that we have done above we put the rcu_read_lock in the driver code where it is needed in a driver dependent way. I think this helps readability of the code so we know where and why we are taking read locks. Most drivers will not need rcu_read_locks here and further XDP drivers already have rcu_read_locks in their code paths for reading xdp programs on RX side so this makes it symmetric where we don't have half of rcu critical sections define in driver and the other half in devmap. Signed-off-by: John Fastabend <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]> Acked-by: Jesper Dangaard Brouer <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 9719c6b commit b23bfa5

File tree

2 files changed

+8
-3
lines changed

2 files changed

+8
-3
lines changed

drivers/net/veth.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ static int veth_xdp_xmit(struct net_device *dev, int n,
377377
unsigned int max_len;
378378
struct veth_rq *rq;
379379

380+
rcu_read_lock();
380381
if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) {
381382
ret = -EINVAL;
382383
goto drop;
@@ -418,11 +419,14 @@ static int veth_xdp_xmit(struct net_device *dev, int n,
418419
if (flags & XDP_XMIT_FLUSH)
419420
__veth_xdp_flush(rq);
420421

421-
if (likely(!drops))
422+
if (likely(!drops)) {
423+
rcu_read_unlock();
422424
return n;
425+
}
423426

424427
ret = n - drops;
425428
drop:
429+
rcu_read_unlock();
426430
atomic64_add(drops, &priv->dropped);
427431

428432
return ret;

kernel/bpf/devmap.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -366,16 +366,17 @@ static int bq_xmit_all(struct xdp_dev_bulk_queue *bq, u32 flags)
366366
* from NET_RX_SOFTIRQ. Either way the poll routine must complete before the
367367
* net device can be torn down. On devmap tear down we ensure the flush list
368368
* is empty before completing to ensure all flush operations have completed.
369+
* When drivers update the bpf program they may need to ensure any flush ops
370+
* are also complete. Using synchronize_rcu or call_rcu will suffice for this
371+
* because both wait for napi context to exit.
369372
*/
370373
void __dev_flush(void)
371374
{
372375
struct list_head *flush_list = this_cpu_ptr(&dev_flush_list);
373376
struct xdp_dev_bulk_queue *bq, *tmp;
374377

375-
rcu_read_lock();
376378
list_for_each_entry_safe(bq, tmp, flush_list, flush_node)
377379
bq_xmit_all(bq, XDP_XMIT_FLUSH);
378-
rcu_read_unlock();
379380
}
380381

381382
/* rcu_read_lock (from syscall and BPF contexts) ensures that if a delete and/or

0 commit comments

Comments
 (0)