During the discussion[0] of Hangbin's multicast patch series, Martin pointed out
that the lifetime of the RCU-protected map entries used by XDP_REDIRECT is by
no means obvious. I promised to look into cleaning this up, and Paul helpfully
provided some hints and a new unrcu_pointer() helper to aid in this.
This is mostly a documentation exercise, clearing up the description of the
lifetime expectations and adding __rcu annotations so sparse and lockdep can
help verify it.
Patches 1-2 are prepatory: Patch 1 adds Paul's unrcu_pointer() helper (which has
already been added to his tree) and patch 2 is a small fix for
dev_get_by_index_rcu() so lockdep understands _bh-disabled access to it. Patch 3
is the main bit that adds the __rcu annotations and updates documentation
comments, and the rest are patches updating the drivers, with one patch per
distinct maintainer.
Unfortunately I don't have any hardware to test any of the driver patches;
Jesper helpfully verified that it doesn't break anything on i40e, but the rest
of the driver patches are only compile-tested.
[0] https://lore.kernel.org/bpf/20210415173551.7ma4slcbqeyiba2r@kafai-mbp.dhcp.thefacebook.com/
Paul E. McKenney (1):
rcu: Create an unrcu_pointer() to remove __rcu from a pointer
Toke Høiland-Jørgensen (16):
bpf: allow RCU-protected lookups to happen from bh context
dev: add rcu_read_lock_bh_held() as a valid check when getting a RCU
dev ref
xdp: add proper __rcu annotations to redirect map entries
ena: remove rcu_read_lock() around XDP program invocation
bnxt: remove rcu_read_lock() around XDP program invocation
thunderx: remove rcu_read_lock() around XDP program invocation
freescale: remove rcu_read_lock() around XDP program invocation
net: intel: remove rcu_read_lock() around XDP program invocation
marvell: remove rcu_read_lock() around XDP program invocation
mlx4: remove rcu_read_lock() around XDP program invocation
nfp: remove rcu_read_lock() around XDP program invocation
qede: remove rcu_read_lock() around XDP program invocation
sfc: remove rcu_read_lock() around XDP program invocation
netsec: remove rcu_read_lock() around XDP program invocation
stmmac: remove rcu_read_lock() around XDP program invocation
net: ti: remove rcu_read_lock() around XDP program invocation
drivers/net/ethernet/amazon/ena/ena_netdev.c | 3 --
drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c | 2 -
.../net/ethernet/cavium/thunder/nicvf_main.c | 2 -
.../net/ethernet/freescale/dpaa/dpaa_eth.c | 8 +--
.../net/ethernet/freescale/dpaa2/dpaa2-eth.c | 3 --
drivers/net/ethernet/intel/i40e/i40e_txrx.c | 2 -
drivers/net/ethernet/intel/i40e/i40e_xsk.c | 6 +--
drivers/net/ethernet/intel/ice/ice_txrx.c | 6 +--
drivers/net/ethernet/intel/ice/ice_xsk.c | 6 +--
drivers/net/ethernet/intel/igb/igb_main.c | 2 -
drivers/net/ethernet/intel/igc/igc_main.c | 7 +--
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 2 -
drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c | 6 +--
.../net/ethernet/intel/ixgbevf/ixgbevf_main.c | 2 -
drivers/net/ethernet/marvell/mvneta.c | 2 -
.../net/ethernet/marvell/mvpp2/mvpp2_main.c | 4 --
drivers/net/ethernet/mellanox/mlx4/en_rx.c | 8 +--
.../ethernet/netronome/nfp/nfp_net_common.c | 2 -
drivers/net/ethernet/qlogic/qede/qede_fp.c | 6 ---
drivers/net/ethernet/sfc/rx.c | 9 +---
drivers/net/ethernet/socionext/netsec.c | 3 --
.../net/ethernet/stmicro/stmmac/stmmac_main.c | 10 +---
drivers/net/ethernet/ti/cpsw_priv.c | 10 +---
include/linux/rcupdate.h | 14 +++++
include/net/xdp_sock.h | 2 +-
kernel/bpf/cpumap.c | 14 +++--
kernel/bpf/devmap.c | 52 ++++++++-----------
kernel/bpf/hashtab.c | 21 +++++---
kernel/bpf/helpers.c | 6 +--
kernel/bpf/lpm_trie.c | 6 ++-
net/core/dev.c | 2 +-
net/core/filter.c | 28 ++++++++++
net/xdp/xsk.c | 4 +-
net/xdp/xsk.h | 4 +-
net/xdp/xskmap.c | 29 ++++++-----
35 files changed, 134 insertions(+), 159 deletions(-)
--
2.31.1
From: "Paul E. McKenney" <paulmck@kernel.org>
The xchg() and cmpxchg() functions are sometimes used to carry out RCU
updates. Unfortunately, this can result in sparse warnings for both
the old-value and new-value arguments, as well as for the return value.
The arguments can be dealt with using RCU_INITIALIZER():
old_p = xchg(&p, RCU_INITIALIZER(new_p));
But a sparse warning still remains due to assigning the __rcu pointer
returned from xchg to the (most likely) non-__rcu pointer old_p.
This commit therefore provides an unrcu_pointer() macro that strips
the __rcu. This macro can be used as follows:
old_p = unrcu_pointer(xchg(&p, RCU_INITIALIZER(new_p)));
Reported-by: Toke Høiland-Jørgensen <redacted>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
include/linux/rcupdate.h | 14 ++++++++++++++
1 file changed, 14 insertions(+)
XDP programs are called from a NAPI poll context, which means the RCU
reference liveness is ensured by local_bh_disable(). Add
rcu_read_lock_bh_held() as a condition to the RCU checks for map lookups so
lockdep understands that the dereferences are safe from inside *either* an
rcu_read_lock() section *or* a local_bh_disable() section. This is done in
preparation for removing the redundant rcu_read_lock()s from the drivers.
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
kernel/bpf/hashtab.c | 21 ++++++++++++++-------
kernel/bpf/helpers.c | 6 +++---
kernel/bpf/lpm_trie.c | 6 ++++--
3 files changed, 21 insertions(+), 12 deletions(-)
The bnxt driver has rcu_read_lock()/rcu_read_unlock() pairs around XDP
program invocations. However, the actual lifetime of the objects referred
by the XDP program invocation is longer, all the way through to the call to
xdp_do_flush(), making the scope of the rcu_read_lock() too small. This
turns out to be harmless because it all happens in a single NAPI poll
cycle (and thus under local_bh_disable()), but it makes the rcu_read_lock()
misleading.
Rather than extend the scope of the rcu_read_lock(), just get rid of it
entirely. With the addition of RCU annotations to the XDP_REDIRECT map
types that take bh execution into account, lockdep even understands this to
be safe, so there's really no reason to keep it around.
Cc: Michael Chan <michael.chan@broadcom.com>
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c | 2 --
1 file changed, 2 deletions(-)
@@ -138,9 +138,7 @@ bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons,xdp_prepare_buff(&xdp,*data_ptr-offset,offset,*len,false);orig_data=xdp.data;-rcu_read_lock();act=bpf_prog_run_xdp(xdp_prog,&xdp);-rcu_read_unlock();tx_avail=bnxt_tx_avail(bp,txr);/* If the tx ring is not full, we must not update the rx producer yet
The ena driver has rcu_read_lock()/rcu_read_unlock() pairs around XDP
program invocations. However, the actual lifetime of the objects referred
by the XDP program invocation is longer, all the way through to the call to
xdp_do_flush(), making the scope of the rcu_read_lock() too small. This
turns out to be harmless because it all happens in a single NAPI poll
cycle (and thus under local_bh_disable()), but it makes the rcu_read_lock()
misleading.
Rather than extend the scope of the rcu_read_lock(), just get rid of it
entirely. With the addition of RCU annotations to the XDP_REDIRECT map
types that take bh execution into account, lockdep even understands this to
be safe, so there's really no reason to keep it around.
Cc: Guy Tzalik <redacted>
Cc: Saeed Bishara <redacted>
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
drivers/net/ethernet/amazon/ena/ena_netdev.c | 3 ---
1 file changed, 3 deletions(-)
XDP_REDIRECT works by a three-step process: the bpf_redirect() and
bpf_redirect_map() helpers will lookup the target of the redirect and store
it (along with some other metadata) in a per-CPU struct bpf_redirect_info.
Next, when the program returns the XDP_REDIRECT return code, the driver
will call xdp_do_redirect() which will use the information thus stored to
actually enqueue the frame into a bulk queue structure (that differs
slightly by map type, but shares the same principle). Finally, before
exiting its NAPI poll loop, the driver will call xdp_do_flush(), which will
flush all the different bulk queues, thus completing the redirect.
Pointers to the map entries will be kept around for this whole sequence of
steps, protected by RCU. However, there is no top-level rcu_read_lock() in
the core code; instead drivers add their own rcu_read_lock() around the XDP
portions of the code, but somewhat inconsistently as Martin discovered[0].
However, things still work because everything happens inside a single NAPI
poll sequence, which means it's between a pair of calls to
local_bh_disable()/local_bh_enable(). So Paul suggested[1] that we could
document this intention by using rcu_dereference_check() with
rcu_read_lock_bh_held() as a second parameter, thus allowing sparse and
lockdep to verify that everything is done correctly.
This patch does just that: we add an __rcu annotation to the map entry
pointers and remove the various comments explaining the NAPI poll assurance
strewn through devmap.c in favour of a longer explanation in filter.c. The
goal is to have one coherent documentation of the entire flow, and rely on
the RCU annotations as a "standard" way of communicating the flow in the
map code (which can additionally be understood by sparse and lockdep).
The RCU annotation replacements result in a fairly straight-forward
replacement where READ_ONCE() becomes rcu_dereference_check(), WRITE_ONCE()
becomes rcu_assign_pointer() and xchg() and cmpxchg() gets wrapped in the
proper constructs to cast the pointer back and forth between __rcu and
__kernel address space (for the benefit of sparse). The one complication is
that xskmap has a few constructions where double-pointers are passed back
and forth; these simply all gain __rcu annotations, and only the final
reference/dereference to the inner-most pointer gets changed.
With this, everything can be run through sparse without eliciting
complaints, and lockdep can verify correctness even without the use of
rcu_read_lock() in the drivers. Subsequent patches will clean these up from
the drivers.
[0] https://lore.kernel.org/bpf/20210415173551.7ma4slcbqeyiba2r@kafai-mbp.dhcp.thefacebook.com/
[1] https://lore.kernel.org/bpf/20210419165837.GA975577@paulmck-ThinkPad-P17-Gen-1/
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
include/net/xdp_sock.h | 2 +-
kernel/bpf/cpumap.c | 14 ++++++++----
kernel/bpf/devmap.c | 52 +++++++++++++++++++-----------------------
net/core/filter.c | 28 +++++++++++++++++++++++
net/xdp/xsk.c | 4 ++--
net/xdp/xsk.h | 4 ++--
net/xdp/xskmap.c | 29 +++++++++++++----------
7 files changed, 83 insertions(+), 50 deletions(-)
@@ -74,7 +74,7 @@ struct bpf_cpu_map_entry {structbpf_cpu_map{structbpf_mapmap;/* Below members specific for map type */-structbpf_cpu_map_entry**cpu_map;+structbpf_cpu_map_entry__rcu**cpu_map;};staticDEFINE_PER_CPU(structlist_head,cpu_map_flush_list);
@@ -562,6 +563,10 @@ static void cpu_map_free(struct bpf_map *map)kfree(cmap);}+/* Elements are kept alive by RCU; either by rcu_read_lock() (from syscall) or+*bylocal_bh_disable()(fromXDPcallsinsideNAPI).The+*rcu_read_lock_bh_held()belowmakeslockdepacceptboth.+*/staticvoid*__cpu_map_lookup_elem(structbpf_map*map,u32key){structbpf_cpu_map*cmap=container_of(map,structbpf_cpu_map,map);
@@ -73,7 +73,7 @@ struct bpf_dtab_netdev {structbpf_dtab{structbpf_mapmap;-structbpf_dtab_netdev**netdev_map;/* DEVMAP type only */+structbpf_dtab_netdev__rcu**netdev_map;/* DEVMAP type only */structlist_headlist;/* these are only used for DEVMAP_HASH type maps */
@@ -259,6 +259,10 @@ static int dev_map_get_next_key(struct bpf_map *map, void *key, void *next_key)return0;}+/* Elements are kept alive by RCU; either by rcu_read_lock() (from syscall) or+*bylocal_bh_disable()(fromXDPcallsinsideNAPI).The+*rcu_read_lock_bh_held()belowmakeslockdepacceptboth.+*/staticvoid*__dev_map_hash_lookup_elem(structbpf_map*map,u32key){structbpf_dtab*dtab=container_of(map,structbpf_dtab,map);
@@ -410,15 +415,9 @@ static void bq_xmit_all(struct xdp_dev_bulk_queue *bq, u32 flags)trace_xdp_devmap_xmit(bq->dev_rx,dev,sent,cnt-sent,err);}-/* __dev_flush is called from xdp_do_flush() which _must_ be signaled-*fromthedriverbeforereturningfromitsnapi->poll()routine.Thepoll()-*routineiscalledeitherfrombusy_pollcontextornet_rx_actionsignaled-*fromNET_RX_SOFTIRQ.Eitherwaythepollroutinemustcompletebeforethe-*netdevicecanbetorndown.Ondevmapteardownweensuretheflushlist-*isemptybeforecompletingtoensureallflushoperationshavecompleted.-*Whendriversupdatethebpfprogramtheymayneedtoensureanyflushops-*arealsocomplete.Usingsynchronize_rcuorcall_rcuwillsufficeforthis-*becausebothwaitfornapicontexttoexit.+/* __dev_flush is called from xdp_do_flush() which _must_ be signalled from the+*driverbeforereturningfromitsnapi->poll()routine.Seethecommentabove+*xdp_do_flush()infilter.c.*/void__dev_flush(void){
@@ -433,9 +432,9 @@ void __dev_flush(void)}}-/* rcu_read_lock (from syscall and BPF contexts) ensures that if a delete and/or-*updatehappensinparallelhereadev_putwon'thappenuntilafterreading-*theifindex.+/* Elements are kept alive by RCU; either by rcu_read_lock() (from syscall) or+*bylocal_bh_disable()(fromXDPcallsinsideNAPI).The+*rcu_read_lock_bh_held()belowmakeslockdepacceptboth.*/staticvoid*__dev_map_lookup_elem(structbpf_map*map,u32key){
@@ -445,12 +444,14 @@ static void *__dev_map_lookup_elem(struct bpf_map *map, u32 key)if(key>=map->max_entries)returnNULL;-obj=READ_ONCE(dtab->netdev_map[key]);+obj=rcu_dereference_check(dtab->netdev_map[key],+rcu_read_lock_bh_held());returnobj;}-/* Runs under RCU-read-side, plus in softirq under NAPI protection.-*Thus,safepercpuvariableaccess.+/* Runs in NAPI, i.e., softirq under local_bh_disable(). Thus, safe percpu+*variableaccess,andmapelementsstickaround.Seecommentabove+*xdp_do_flush()infilter.c.*/staticvoidbq_enqueue(structnet_device*dev,structxdp_frame*xdpf,structnet_device*dev_rx,structbpf_prog*xdp_prog)
@@ -735,14 +736,7 @@ static int dev_map_delete_elem(struct bpf_map *map, void *key)if(k>=map->max_entries)return-EINVAL;-/* Use call_rcu() here to ensure any rcu critical sections have-*completedaswellasanyflushoperationsbecausecall_rcu-*willwaitforpreempt-disableregiontocomplete,NAPIinthis-*context.Andadditionally,thedriverteardownensuresall-*softirqsarecompletebeforeremovingthenetdeviceinthe-*caseofdev_putequalszero.-*/-old_dev=xchg(&dtab->netdev_map[k],NULL);+old_dev=unrcu_pointer(xchg(&dtab->netdev_map[k],NULL));if(old_dev)call_rcu(&old_dev->rcu,__dev_map_entry_free);return0;
@@ -851,7 +845,7 @@ static int __dev_map_update_elem(struct net *net, struct bpf_map *map,*Rememberingthedriversideflushoperationwillhappenbeforethe*netdeviceisremoved.*/-old_dev=xchg(&dtab->netdev_map[i],dev);+old_dev=unrcu_pointer(xchg(&dtab->netdev_map[i],RCU_INITIALIZER(dev)));if(old_dev)call_rcu(&old_dev->rcu,__dev_map_entry_free);
@@ -1031,10 +1025,10 @@ static int dev_map_notification(struct notifier_block *notifier,for(i=0;i<dtab->map.max_entries;i++){structbpf_dtab_netdev*dev,*odev;-dev=READ_ONCE(dtab->netdev_map[i]);+dev=rcu_dereference(dtab->netdev_map[i]);if(!dev||netdev!=dev->dev)continue;-odev=cmpxchg(&dtab->netdev_map[i],dev,NULL);+odev=unrcu_pointer(cmpxchg(&dtab->netdev_map[i],RCU_INITIALIZER(dev),NULL));if(dev==odev)call_rcu(&dev->rcu,__dev_map_entry_free);
@@ -3922,6 +3922,34 @@ static const struct bpf_func_proto bpf_xdp_adjust_meta_proto = {.arg2_type=ARG_ANYTHING,};+/* XDP_REDIRECT works by a three-step process, implemented in the functions+*below:+*+*1.Thebpf_redirect()andbpf_redirect_map()helperswilllookupthetarget+*oftheredirectandstoreit(alongwithsomeothermetadata)inaper-CPU+*structbpf_redirect_info.+*+*2.WhentheprogramreturnstheXDP_REDIRECTreturncode,thedriverwill+*callxdp_do_redirect()whichwillusetheinformationinstruct+*bpf_redirect_infotoactuallyenqueuetheframeintoamaptype-specific+*bulkqueuestructure.+*+*3.BeforeexitingitsNAPIpollloop,thedriverwillcallxdp_do_flush(),+*whichwillflushallthedifferentbulkqueues,thuscompletingthe+*redirect.+*+*Pointerstothemapentrieswillbekeptaroundforthiswholesequenceof+*steps,protectedbyRCU.However,thereisnotop-levelrcu_read_lock()in+*thecorecode;instead,theRCUprotectionreliesoneverythinghappening+*insideasingleNAPIpollsequence,whichmeansit'sbetweenapairofcalls+*tolocal_bh_disable()/local_bh_enable().+*+*Themapentriesaremarkedas__rcuandthemapcodemakessureto+*dereferencethosepointerswithrcu_dereference_check()inawaythatworks+*forbothsectionsthattoholdanrcu_read_lock()andsectionsthatare+*calledfromNAPIwithoutaseparatercu_read_lock().Thecodebelowdoesnot+*useRCUannotations,butreliesonthoseinthemapcode.+*/voidxdp_do_flush(void){__dev_flush();
@@ -124,6 +124,10 @@ static int xsk_map_gen_lookup(struct bpf_map *map, struct bpf_insn *insn_buf)returninsn-insn_buf;}+/* Elements are kept alive by RCU; either by rcu_read_lock() (from syscall) or+*bylocal_bh_disable()(fromXDPcallsinsideNAPI).The+*rcu_read_lock_bh_held()belowmakeslockdepacceptboth.+*/staticvoid*__xsk_map_lookup_elem(structbpf_map*map,u32key){structxsk_map*m=container_of(map,structxsk_map,map);
Some of the XDP helpers (in particular, xdp_do_redirect()) will get a
struct net_device reference using dev_get_by_index_rcu(). These are called
from a NAPI poll context, which means the RCU reference liveness is ensured
by local_bh_disable(). Add rcu_read_lock_bh_held() as a condition to the
RCU list traversal in dev_get_by_index_rcu() so lockdep understands that
the dereferences are safe from *both* an rcu_read_lock() *and* with
local_bh_disable().
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
net/core/dev.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
The Intel drivers all have rcu_read_lock()/rcu_read_unlock() pairs around
XDP program invocations. However, the actual lifetime of the objects
referred by the XDP program invocation is longer, all the way through to
the call to xdp_do_flush(), making the scope of the rcu_read_lock() too
small. This turns out to be harmless because it all happens in a single
NAPI poll cycle (and thus under local_bh_disable()), but it makes the
rcu_read_lock() misleading.
Rather than extend the scope of the rcu_read_lock(), just get rid of it
entirely. With the addition of RCU annotations to the XDP_REDIRECT map
types that take bh execution into account, lockdep even understands this to
be safe, so there's really no reason to keep it around.
Cc: Jesse Brandeburg <redacted>
Cc: Tony Nguyen <anthony.l.nguyen@intel.com>
Cc: intel-wired-lan@lists.osuosl.org
Tested-by: Jesper Dangaard Brouer <redacted> # i40e
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
drivers/net/ethernet/intel/i40e/i40e_txrx.c | 2 --
drivers/net/ethernet/intel/i40e/i40e_xsk.c | 6 +-----
drivers/net/ethernet/intel/ice/ice_txrx.c | 6 +-----
drivers/net/ethernet/intel/ice/ice_xsk.c | 6 +-----
drivers/net/ethernet/intel/igb/igb_main.c | 2 --
drivers/net/ethernet/intel/igc/igc_main.c | 7 ++-----
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 2 --
drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c | 6 +-----
drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 2 --
9 files changed, 6 insertions(+), 33 deletions(-)
@@ -153,7 +153,6 @@ static int i40e_run_xdp_zc(struct i40e_ring *rx_ring, struct xdp_buff *xdp)structbpf_prog*xdp_prog;u32act;-rcu_read_lock();/* NB! xdp_prog will always be !NULL, due to the fact that*thispathisenabledbysettinganXDPprogram.*/
@@ -1129,15 +1129,11 @@ int ice_clean_rx_irq(struct ice_ring *rx_ring, int budget)xdp.frame_sz=ice_rx_frame_truesize(rx_ring,size);#endif-rcu_read_lock();xdp_prog=READ_ONCE(rx_ring->xdp_prog);-if(!xdp_prog){-rcu_read_unlock();+if(!xdp_prog)gotoconstruct_skb;-}xdp_res=ice_run_xdp(rx_ring,&xdp,xdp_prog);-rcu_read_unlock();if(!xdp_res)gotoconstruct_skb;if(xdp_res&(ICE_XDP_TX|ICE_XDP_REDIR)){
@@ -463,7 +463,6 @@ ice_run_xdp_zc(struct ice_ring *rx_ring, struct xdp_buff *xdp)structice_ring*xdp_ring;u32act;-rcu_read_lock();/* ZC patch is enabled only when XDP program is set,*sohereitcannotbeNULL*/
The thunderx driver has rcu_read_lock()/rcu_read_unlock() pairs around XDP
program invocations. However, the actual lifetime of the objects referred
by the XDP program invocation is longer, all the way through to the call to
xdp_do_flush(), making the scope of the rcu_read_lock() too small. This
turns out to be harmless because it all happens in a single NAPI poll
cycle (and thus under local_bh_disable()), but it makes the rcu_read_lock()
misleading.
Rather than extend the scope of the rcu_read_lock(), just get rid of it
entirely. With the addition of RCU annotations to the XDP_REDIRECT map
types that take bh execution into account, lockdep even understands this to
be safe, so there's really no reason to keep it around.
Cc: Sunil Goutham <sgoutham@marvell.com>
Cc: linux-arm-kernel@lists.infradead.org
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
drivers/net/ethernet/cavium/thunder/nicvf_main.c | 2 --
1 file changed, 2 deletions(-)
The dpaa and dpaa2 drivers have rcu_read_lock()/rcu_read_unlock() pairs
around XDP program invocations. However, the actual lifetime of the objects
referred by the XDP program invocation is longer, all the way through to
the call to xdp_do_flush(), making the scope of the rcu_read_lock() too
small. This turns out to be harmless because it all happens in a single
NAPI poll cycle (and thus under local_bh_disable()), but it makes the
rcu_read_lock() misleading.
Rather than extend the scope of the rcu_read_lock(), just get rid of it
entirely. With the addition of RCU annotations to the XDP_REDIRECT map
types that take bh execution into account, lockdep even understands this to
be safe, so there's really no reason to keep it around.
Cc: Madalin Bucur <madalin.bucur@nxp.com>
Cc: Ioana Ciornei <ioana.ciornei@nxp.com>
Cc: Ioana Radulescu <redacted>
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 8 +-------
drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 3 ---
2 files changed, 1 insertion(+), 10 deletions(-)
The stmmac driver has rcu_read_lock()/rcu_read_unlock() pairs around XDP
program invocations. However, the actual lifetime of the objects referred
by the XDP program invocation is longer, all the way through to the call to
xdp_do_flush(), making the scope of the rcu_read_lock() too small. This
turns out to be harmless because it all happens in a single NAPI poll
cycle (and thus under local_bh_disable()), but it makes the rcu_read_lock()
misleading.
Rather than extend the scope of the rcu_read_lock(), just get rid of it
entirely. With the addition of RCU annotations to the XDP_REDIRECT map
types that take bh execution into account, lockdep even understands this to
be safe, so there's really no reason to keep it around.
Cc: Giuseppe Cavallaro <redacted>
Cc: Alexandre Torgue <alexandre.torgue@foss.st.com>
Cc: Jose Abreu <redacted>
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
@@ -4654,7 +4654,6 @@ static int stmmac_xdp_xmit_back(struct stmmac_priv *priv,returnres;}-/* This function assumes rcu_read_lock() is held by the caller. */staticint__stmmac_xdp_run_prog(structstmmac_priv*priv,structbpf_prog*prog,structxdp_buff*xdp)
The netsec driver has a rcu_read_lock()/rcu_read_unlock() pair around the
full RX loop, covering everything up to and including xdp_do_flush(). This
is actually the correct behaviour, but because it all happens in a single
NAPI poll cycle (and thus under local_bh_disable()), it is also technically
redundant.
With the addition of RCU annotations to the XDP_REDIRECT map types that
take bh execution into account, lockdep even understands this to be safe,
so there's really no reason to keep the rcu_read_lock() around anymore, so
let's just remove it.
Cc: Jassi Brar <redacted>
Cc: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
drivers/net/ethernet/socionext/netsec.c | 3 ---
1 file changed, 3 deletions(-)
The sfc driver has rcu_read_lock()/rcu_read_unlock() pairs around XDP
program invocations. However, the actual lifetime of the objects referred
by the XDP program invocation is longer, all the way through to the call to
xdp_do_flush(), making the scope of the rcu_read_lock() too small. This
turns out to be harmless because it all happens in a single NAPI poll
cycle (and thus under local_bh_disable()), but it makes the rcu_read_lock()
misleading.
Rather than extend the scope of the rcu_read_lock(), just get rid of it
entirely. With the addition of RCU annotations to the XDP_REDIRECT map
types that take bh execution into account, lockdep even understands this to
be safe, so there's really no reason to keep it around.
Cc: Edward Cree <ecree.xilinx@gmail.com>
Cc: Martin Habets <redacted>
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
drivers/net/ethernet/sfc/rx.c | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
The cpsw driver has rcu_read_lock()/rcu_read_unlock() pairs around XDP
program invocations. However, the actual lifetime of the objects referred
by the XDP program invocation is longer, all the way through to the call to
xdp_do_flush(), making the scope of the rcu_read_lock() too small. This
turns out to be harmless because it all happens in a single NAPI poll
cycle (and thus under local_bh_disable()), but it makes the rcu_read_lock()
misleading.
Rather than extend the scope of the rcu_read_lock(), just get rid of it
entirely. With the addition of RCU annotations to the XDP_REDIRECT map
types that take bh execution into account, lockdep even understands this to
be safe, so there's really no reason to keep it around.
Cc: Grygorii Strashko <grygorii.strashko@ti.com>
Cc: linux-omap@vger.kernel.org
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
drivers/net/ethernet/ti/cpsw_priv.c | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
@@ -1328,13 +1328,9 @@ int cpsw_run_xdp(struct cpsw_priv *priv, int ch, struct xdp_buff *xdp,structbpf_prog*prog;u32act;-rcu_read_lock();-prog=READ_ONCE(priv->xdp_prog);-if(!prog){-ret=CPSW_XDP_PASS;-gotoout;-}+if(!prog)+returnCPSW_XDP_PASS;act=bpf_prog_run_xdp(prog,xdp);/* XDP prog might have changed packet data and boundaries */
@@ -1378,10 +1374,8 @@ int cpsw_run_xdp(struct cpsw_priv *priv, int ch, struct xdp_buff *xdp,ndev->stats.rx_bytes+=*len;ndev->stats.rx_packets++;out:-rcu_read_unlock();returnret;drop:-rcu_read_unlock();page_pool_recycle_direct(cpsw->page_pool[ch],page);returnret;}
The mlx4 driver has rcu_read_lock()/rcu_read_unlock() pairs around XDP
program invocations. However, the actual lifetime of the objects referred
by the XDP program invocation is longer, all the way through to the call to
xdp_do_flush(), making the scope of the rcu_read_lock() too small. This
turns out to be harmless because it all happens in a single NAPI poll
cycle (and thus under local_bh_disable()), but it makes the rcu_read_lock()
misleading.
Rather than extend the scope of the rcu_read_lock(), just get rid of it
entirely. With the addition of RCU annotations to the XDP_REDIRECT map
types that take bh execution into account, lockdep even understands this to
be safe, so there's really no reason to keep it around. Also switch the RCU
dereferences in the driver loop itself to the _bh variants.
Cc: Tariq Toukan <tariqt@nvidia.com>
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
drivers/net/ethernet/mellanox/mlx4/en_rx.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
@@ -679,9 +679,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budring=priv->rx_ring[cq_ring];-/* Protect accesses to: ring->xdp_prog, priv->mac_hash list */-rcu_read_lock();-xdp_prog=rcu_dereference(ring->xdp_prog);+xdp_prog=rcu_dereference_bh(ring->xdp_prog);xdp_init_buff(&xdp,priv->frag_info[0].frag_stride,&ring->xdp_rxq);doorbell_pending=false;
@@ -744,7 +742,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud/* Drop the packet, since HW loopback-ed it */mac_hash=ethh->h_source[MLX4_EN_MAC_HASH_IDX];bucket=&priv->mac_hash[mac_hash];-hlist_for_each_entry_rcu(entry,bucket,hlist){+hlist_for_each_entry_rcu_bh(entry,bucket,hlist){if(ether_addr_equal_64bits(entry->mac,ethh->h_source))gotonext;
@@ -899,8 +897,6 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int budbreak;}-rcu_read_unlock();-if(likely(polled)){if(doorbell_pending){priv->tx_cq[TX_XDP][cq_ring]->xdp_busy=true;
The nfp driver has rcu_read_lock()/rcu_read_unlock() pairs around XDP
program invocations. However, the actual lifetime of the objects referred
by the XDP program invocation is longer, all the way through to the call to
xdp_do_flush(), making the scope of the rcu_read_lock() too small.
While this is not actually an issue for the nfp driver because it doesn't
support XDP_REDIRECT (and thus doesn't call xdp_do_flush()), the
rcu_read_lock() is still unneeded. And With the addition of RCU annotations
to the XDP_REDIRECT map types that take bh execution into account, lockdep
even understands this to be safe, so there's really no reason to keep it
around.
Cc: Simon Horman <redacted>
Cc: oss-drivers@netronome.com
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 2 --
1 file changed, 2 deletions(-)
The qede driver has rcu_read_lock()/rcu_read_unlock() pairs around XDP
program invocations. However, the actual lifetime of the objects referred
by the XDP program invocation is longer, all the way through to the call to
xdp_do_flush(), making the scope of the rcu_read_lock() too small. This
turns out to be harmless because it all happens in a single NAPI poll
cycle (and thus under local_bh_disable()), but it makes the rcu_read_lock()
misleading.
Rather than extend the scope of the rcu_read_lock(), just get rid of it
entirely. With the addition of RCU annotations to the XDP_REDIRECT map
types that take bh execution into account, lockdep even understands this to
be safe, so there's really no reason to keep it around.
Cc: Ariel Elior <redacted>
Cc: GR-everest-linux-l2@marvell.com
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
drivers/net/ethernet/qlogic/qede/qede_fp.c | 6 ------
1 file changed, 6 deletions(-)
@@ -1089,13 +1089,7 @@ static bool qede_rx_xdp(struct qede_dev *edev,xdp_prepare_buff(&xdp,page_address(bd->data),*data_offset,*len,false);-/* Queues always have a full reset currently, so for the time-*beinguntilthere'satomicprogramreplacejustmarkread-*sideformaphelpers.-*/-rcu_read_lock();act=bpf_prog_run_xdp(prog,&xdp);-rcu_read_unlock();/* Recalculate, as XDP might have changed the headers */*data_offset=xdp.data-xdp.data_hard_start;
The mvneta and mvpp2 drivers have rcu_read_lock()/rcu_read_unlock() pairs
around XDP program invocations. However, the actual lifetime of the objects
referred by the XDP program invocation is longer, all the way through to
the call to xdp_do_flush(), making the scope of the rcu_read_lock() too
small. This turns out to be harmless because it all happens in a single
NAPI poll cycle (and thus under local_bh_disable()), but it makes the
rcu_read_lock() misleading.
Rather than extend the scope of the rcu_read_lock(), just get rid of it
entirely. With the addition of RCU annotations to the XDP_REDIRECT map
types that take bh execution into account, lockdep even understands this to
be safe, so there's really no reason to keep it around.
Cc: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
Cc: Marcin Wojtas <redacted>
Cc: Russell King <linux@armlinux.org.uk>
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
drivers/net/ethernet/marvell/mvneta.c | 2 --
drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 4 ----
2 files changed, 6 deletions(-)
@@ -2370,7 +2370,6 @@ static int mvneta_rx_swbm(struct napi_struct *napi,/* Get number of received packets */rx_todo=mvneta_rxq_busy_desc_num_get(pp,rxq);-rcu_read_lock();xdp_prog=READ_ONCE(pp->xdp_prog);/* Fairness NAPI loop */
@@ -2448,7 +2447,6 @@ static int mvneta_rx_swbm(struct napi_struct *napi,xdp_buf.data_hard_start=NULL;sinfo.nr_frags=0;}-rcu_read_unlock();if(xdp_buf.data_hard_start)mvneta_xdp_put_buff(pp,rxq,&xdp_buf,&sinfo,-1);
@@ -3852,8 +3852,6 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,intrx_done=0;u32xdp_ret=0;-rcu_read_lock();-xdp_prog=READ_ONCE(port->xdp_prog);/* Get number of received packets and clamp the to-do */
From: Edward Cree <ecree.xilinx@gmail.com> Date: 2021-06-09 12:16:14
On 09/06/2021 11:33, Toke Høiland-Jørgensen wrote:
The sfc driver has rcu_read_lock()/rcu_read_unlock() pairs around XDP
program invocations. However, the actual lifetime of the objects referred
by the XDP program invocation is longer, all the way through to the call to
xdp_do_flush(), making the scope of the rcu_read_lock() too small. This
turns out to be harmless because it all happens in a single NAPI poll
cycle (and thus under local_bh_disable()), but it makes the rcu_read_lock()
misleading.
Rather than extend the scope of the rcu_read_lock(), just get rid of it
entirely. With the addition of RCU annotations to the XDP_REDIRECT map
types that take bh execution into account, lockdep even understands this to
be safe, so there's really no reason to keep it around.
Cc: Edward Cree <ecree.xilinx@gmail.com>
Cc: Martin Habets <redacted>
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
From: "Paul E. McKenney" <paulmck@kernel.org> Date: 2021-06-09 13:57:27
On Wed, Jun 09, 2021 at 12:33:14PM +0200, Toke Høiland-Jørgensen wrote:
The ena driver has rcu_read_lock()/rcu_read_unlock() pairs around XDP
program invocations. However, the actual lifetime of the objects referred
by the XDP program invocation is longer, all the way through to the call to
xdp_do_flush(), making the scope of the rcu_read_lock() too small. This
turns out to be harmless because it all happens in a single NAPI poll
cycle (and thus under local_bh_disable()), but it makes the rcu_read_lock()
misleading.
Rather than extend the scope of the rcu_read_lock(), just get rid of it
entirely. With the addition of RCU annotations to the XDP_REDIRECT map
types that take bh execution into account, lockdep even understands this to
be safe, so there's really no reason to keep it around.
It might be worth adding a comment, perhaps where the rcu_read_lock()
used to be, stating what the protection is. Maybe something like this?
/*
* This code is invoked within a single NAPI poll cycle
* and thus under local_bh_disable(), which provides the
* needed RCU protection.
*/
Thanx, Paul
From: "Paul E. McKenney" <paulmck@kernel.org> Date: 2021-06-09 13:58:35
On Wed, Jun 09, 2021 at 12:33:15PM +0200, Toke Høiland-Jørgensen wrote:
The bnxt driver has rcu_read_lock()/rcu_read_unlock() pairs around XDP
program invocations. However, the actual lifetime of the objects referred
by the XDP program invocation is longer, all the way through to the call to
xdp_do_flush(), making the scope of the rcu_read_lock() too small. This
turns out to be harmless because it all happens in a single NAPI poll
cycle (and thus under local_bh_disable()), but it makes the rcu_read_lock()
misleading.
Rather than extend the scope of the rcu_read_lock(), just get rid of it
entirely. With the addition of RCU annotations to the XDP_REDIRECT map
types that take bh execution into account, lockdep even understands this to
be safe, so there's really no reason to keep it around.
And same for the rest of these removals. Someone might be very happy
to have that comment at some later date, and that someone just might
be you. ;-)
Thanx, Paul
@@ -138,9 +138,7 @@ bool bnxt_rx_xdp(struct bnxt *bp, struct bnxt_rx_ring_info *rxr, u16 cons,xdp_prepare_buff(&xdp,*data_ptr-offset,offset,*len,false);orig_data=xdp.data;-rcu_read_lock();act=bpf_prog_run_xdp(xdp_prog,&xdp);-rcu_read_unlock();tx_avail=bnxt_tx_avail(bp,txr);/* If the tx ring is not full, we must not update the rx producer yet
On 09/06/2021 13:33, Toke Høiland-Jørgensen wrote:
The cpsw driver has rcu_read_lock()/rcu_read_unlock() pairs around XDP
program invocations. However, the actual lifetime of the objects referred
by the XDP program invocation is longer, all the way through to the call to
xdp_do_flush(), making the scope of the rcu_read_lock() too small. This
turns out to be harmless because it all happens in a single NAPI poll
cycle (and thus under local_bh_disable()), but it makes the rcu_read_lock()
misleading.
Rather than extend the scope of the rcu_read_lock(), just get rid of it
entirely. With the addition of RCU annotations to the XDP_REDIRECT map
types that take bh execution into account, lockdep even understands this to
be safe, so there's really no reason to keep it around.
Cc: Grygorii Strashko <grygorii.strashko@ti.com>
Cc: linux-omap@vger.kernel.org
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
drivers/net/ethernet/ti/cpsw_priv.c | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
From: Yonghong Song <hidden> Date: 2021-06-10 00:18:57
On 6/9/21 3:33 AM, Toke Høiland-Jørgensen wrote:
During the discussion[0] of Hangbin's multicast patch series, Martin pointed out
that the lifetime of the RCU-protected map entries used by XDP_REDIRECT is by
no means obvious. I promised to look into cleaning this up, and Paul helpfully
provided some hints and a new unrcu_pointer() helper to aid in this.
This is mostly a documentation exercise, clearing up the description of the
lifetime expectations and adding __rcu annotations so sparse and lockdep can
help verify it.
Patches 1-2 are prepatory: Patch 1 adds Paul's unrcu_pointer() helper (which has
already been added to his tree) and patch 2 is a small fix for
dev_get_by_index_rcu() so lockdep understands _bh-disabled access to it. Patch 3
is the main bit that adds the __rcu annotations and updates documentation
comments, and the rest are patches updating the drivers, with one patch per
distinct maintainer.
Unfortunately I don't have any hardware to test any of the driver patches;
Jesper helpfully verified that it doesn't break anything on i40e, but the rest
of the driver patches are only compile-tested.
[0] https://lore.kernel.org/bpf/20210415173551.7ma4slcbqeyiba2r@kafai-mbp.dhcp.thefacebook.com/
Paul E. McKenney (1):
rcu: Create an unrcu_pointer() to remove __rcu from a pointer
Toke Høiland-Jørgensen (16):
bpf: allow RCU-protected lookups to happen from bh context
dev: add rcu_read_lock_bh_held() as a valid check when getting a RCU
dev ref
xdp: add proper __rcu annotations to redirect map entries
ena: remove rcu_read_lock() around XDP program invocation
bnxt: remove rcu_read_lock() around XDP program invocation
thunderx: remove rcu_read_lock() around XDP program invocation
freescale: remove rcu_read_lock() around XDP program invocation
net: intel: remove rcu_read_lock() around XDP program invocation
marvell: remove rcu_read_lock() around XDP program invocation
mlx4: remove rcu_read_lock() around XDP program invocation
nfp: remove rcu_read_lock() around XDP program invocation
qede: remove rcu_read_lock() around XDP program invocation
sfc: remove rcu_read_lock() around XDP program invocation
netsec: remove rcu_read_lock() around XDP program invocation
stmmac: remove rcu_read_lock() around XDP program invocation
net: ti: remove rcu_read_lock() around XDP program invocation
drivers/net/ethernet/amazon/ena/ena_netdev.c | 3 --
drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c | 2 -
.../net/ethernet/cavium/thunder/nicvf_main.c | 2 -
.../net/ethernet/freescale/dpaa/dpaa_eth.c | 8 +--
.../net/ethernet/freescale/dpaa2/dpaa2-eth.c | 3 --
drivers/net/ethernet/intel/i40e/i40e_txrx.c | 2 -
drivers/net/ethernet/intel/i40e/i40e_xsk.c | 6 +--
drivers/net/ethernet/intel/ice/ice_txrx.c | 6 +--
drivers/net/ethernet/intel/ice/ice_xsk.c | 6 +--
drivers/net/ethernet/intel/igb/igb_main.c | 2 -
drivers/net/ethernet/intel/igc/igc_main.c | 7 +--
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 2 -
drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c | 6 +--
.../net/ethernet/intel/ixgbevf/ixgbevf_main.c | 2 -
drivers/net/ethernet/marvell/mvneta.c | 2 -
.../net/ethernet/marvell/mvpp2/mvpp2_main.c | 4 --
drivers/net/ethernet/mellanox/mlx4/en_rx.c | 8 +--
.../ethernet/netronome/nfp/nfp_net_common.c | 2 -
drivers/net/ethernet/qlogic/qede/qede_fp.c | 6 ---
drivers/net/ethernet/sfc/rx.c | 9 +---
drivers/net/ethernet/socionext/netsec.c | 3 --
.../net/ethernet/stmicro/stmmac/stmmac_main.c | 10 +---
drivers/net/ethernet/ti/cpsw_priv.c | 10 +---
include/linux/rcupdate.h | 14 +++++
include/net/xdp_sock.h | 2 +-
kernel/bpf/cpumap.c | 14 +++--
kernel/bpf/devmap.c | 52 ++++++++-----------
kernel/bpf/hashtab.c | 21 +++++---
kernel/bpf/helpers.c | 6 +--
kernel/bpf/lpm_trie.c | 6 ++-
net/core/dev.c | 2 +-
net/core/filter.c | 28 ++++++++++
net/xdp/xsk.c | 4 +-
net/xdp/xsk.h | 4 +-
net/xdp/xskmap.c | 29 ++++++-----
35 files changed, 134 insertions(+), 159 deletions(-)
Martin, could you help review this patch set? You had participated
in early discussions related to this patch. Thanks!
On Wed, 9 Jun 2021 at 13:33, Toke Høiland-Jørgensen [off-list ref] wrote:
quoted hunk
The netsec driver has a rcu_read_lock()/rcu_read_unlock() pair around the
full RX loop, covering everything up to and including xdp_do_flush(). This
is actually the correct behaviour, but because it all happens in a single
NAPI poll cycle (and thus under local_bh_disable()), it is also technically
redundant.
With the addition of RCU annotations to the XDP_REDIRECT map types that
take bh execution into account, lockdep even understands this to be safe,
so there's really no reason to keep the rcu_read_lock() around anymore, so
let's just remove it.
Cc: Jassi Brar <redacted>
Cc: Ilias Apalodimas <ilias.apalodimas@linaro.org>
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
drivers/net/ethernet/socionext/netsec.c | 3 ---
1 file changed, 3 deletions(-)
On 6/9/2021 1:33 PM, Toke Høiland-Jørgensen wrote:
The mlx4 driver has rcu_read_lock()/rcu_read_unlock() pairs around XDP
program invocations. However, the actual lifetime of the objects referred
by the XDP program invocation is longer, all the way through to the call to
xdp_do_flush(), making the scope of the rcu_read_lock() too small. This
turns out to be harmless because it all happens in a single NAPI poll
cycle (and thus under local_bh_disable()), but it makes the rcu_read_lock()
misleading.
Rather than extend the scope of the rcu_read_lock(), just get rid of it
entirely. With the addition of RCU annotations to the XDP_REDIRECT map
types that take bh execution into account, lockdep even understands this to
be safe, so there's really no reason to keep it around. Also switch the RCU
dereferences in the driver loop itself to the _bh variants.
Cc: Tariq Toukan <tariqt@nvidia.com>
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
Thanks for your patch.
Reviewed-by: Tariq Toukan <tariqt@nvidia.com>
Regards,
Tariq
On Wed, Jun 09, 2021 at 12:33:15PM +0200, Toke Høiland-Jørgensen wrote:
quoted
The bnxt driver has rcu_read_lock()/rcu_read_unlock() pairs around XDP
program invocations. However, the actual lifetime of the objects referred
by the XDP program invocation is longer, all the way through to the call to
xdp_do_flush(), making the scope of the rcu_read_lock() too small. This
turns out to be harmless because it all happens in a single NAPI poll
cycle (and thus under local_bh_disable()), but it makes the rcu_read_lock()
misleading.
Rather than extend the scope of the rcu_read_lock(), just get rid of it
entirely. With the addition of RCU annotations to the XDP_REDIRECT map
types that take bh execution into account, lockdep even understands this to
be safe, so there's really no reason to keep it around.
And same for the rest of these removals. Someone might be very happy
to have that comment at some later date, and that someone just might
be you. ;-)
Bah, why do you have to go and make sensible suggestions like that? ;)
Will wait for Martin's review and add this in a v2. BTW, is it OK to
include your patch in the series like this, or should I rather request
that your tree be merged into bpf-next?
-Toke
On Wed, Jun 9, 2021 at 7:24 AM Toke Høiland-Jørgensen [off-list ref] wrote:
quoted hunk
XDP programs are called from a NAPI poll context, which means the RCU
reference liveness is ensured by local_bh_disable(). Add
rcu_read_lock_bh_held() as a condition to the RCU checks for map lookups so
lockdep understands that the dereferences are safe from inside *either* an
rcu_read_lock() section *or* a local_bh_disable() section. This is done in
preparation for removing the redundant rcu_read_lock()s from the drivers.
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
kernel/bpf/hashtab.c | 21 ++++++++++++++-------
kernel/bpf/helpers.c | 6 +++---
kernel/bpf/lpm_trie.c | 6 ++++--
3 files changed, 21 insertions(+), 12 deletions(-)
It's not clear to me whether rcu_read_lock_held() is still needed.
All comments sound like rcu_read_lock_bh_held() is a superset of rcu
that includes bh.
But reading rcu source code it looks like RCU_BH is its own rcu flavor...
which is confusing.
From: Martin KaFai Lau <hidden> Date: 2021-06-10 19:33:36
On Wed, Jun 09, 2021 at 12:33:11PM +0200, Toke Høiland-Jørgensen wrote:
quoted hunk
XDP programs are called from a NAPI poll context, which means the RCU
reference liveness is ensured by local_bh_disable(). Add
rcu_read_lock_bh_held() as a condition to the RCU checks for map lookups so
lockdep understands that the dereferences are safe from inside *either* an
rcu_read_lock() section *or* a local_bh_disable() section. This is done in
preparation for removing the redundant rcu_read_lock()s from the drivers.
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
kernel/bpf/hashtab.c | 21 ++++++++++++++-------
kernel/bpf/helpers.c | 6 +++---
kernel/bpf/lpm_trie.c | 6 ++++--
3 files changed, 21 insertions(+), 12 deletions(-)
There is a discrepancy in rcu_read_lock_trace_held() here but
I think the patch_map_ops_generic step in the verifier has skipped
these helper calls. It is unrelated and can be addressed later
until it is needed.
Acked-by: Martin KaFai Lau <redacted>
From: Martin KaFai Lau <hidden> Date: 2021-06-10 19:37:29
On Wed, Jun 09, 2021 at 12:33:12PM +0200, Toke Høiland-Jørgensen wrote:
quoted hunk
Some of the XDP helpers (in particular, xdp_do_redirect()) will get a
struct net_device reference using dev_get_by_index_rcu(). These are called
from a NAPI poll context, which means the RCU reference liveness is ensured
by local_bh_disable(). Add rcu_read_lock_bh_held() as a condition to the
RCU list traversal in dev_get_by_index_rcu() so lockdep understands that
the dereferences are safe from *both* an rcu_read_lock() *and* with
local_bh_disable().
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
net/core/dev.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Daniel Borkmann <daniel@iogearbox.net> Date: 2021-06-10 21:24:25
Hi Paul,
On 6/10/21 8:38 PM, Alexei Starovoitov wrote:
On Wed, Jun 9, 2021 at 7:24 AM Toke Høiland-Jørgensen [off-list ref] wrote:
quoted
XDP programs are called from a NAPI poll context, which means the RCU
reference liveness is ensured by local_bh_disable(). Add
rcu_read_lock_bh_held() as a condition to the RCU checks for map lookups so
lockdep understands that the dereferences are safe from inside *either* an
rcu_read_lock() section *or* a local_bh_disable() section. This is done in
preparation for removing the redundant rcu_read_lock()s from the drivers.
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
kernel/bpf/hashtab.c | 21 ++++++++++++++-------
kernel/bpf/helpers.c | 6 +++---
kernel/bpf/lpm_trie.c | 6 ++++--
3 files changed, 21 insertions(+), 12 deletions(-)
It's not clear to me whether rcu_read_lock_held() is still needed.
All comments sound like rcu_read_lock_bh_held() is a superset of rcu
that includes bh.
But reading rcu source code it looks like RCU_BH is its own rcu flavor...
which is confusing.
The series is a bit confusing to me as well. I recall we had a discussion with
Paul, but it was back in 2016 aka very early days of XDP to get some clarifications
about RCU vs RCU-bh flavour on this. Paul, given the series in here, I assume the
below is not true anymore, and in this case (since we're removing rcu_read_lock()
from drivers), the RCU-bh acts as a real superset?
Back then from your clarifications this was not the case:
On Mon, Jul 25, 2016 at 11:26:02AM -0700, Alexei Starovoitov wrote:
> On Mon, Jul 25, 2016 at 11:03 AM, Paul E. McKenney
> [off-list ref] wrote:
[...]
>>> The crux of the question is whether a particular driver rx handler, when
>>> called from __do_softirq, needs to add an additional rcu_read_lock or
>>> whether it can rely on the mechanics of softirq.
>>
>> If it was rcu_read_lock_bh(), you could.
>>
>> But you didn't say rcu_read_lock_bh(), you instead said rcu_read_lock(),
>> which means that you absolutely cannot rely on softirq semantics.
>>
>> In particular, in CONFIG_PREEMPT=y kernels, rcu_preempt_check_callbacks()
>> will notice that there is no rcu_read_lock() in effect and report
>> a quiescent state for that CPU. Because rcu_preempt_check_callbacks()
>> is invoked from the scheduling-clock interrupt, it absolutely can
>> execute during do_softirq(), and therefore being in softirq context
>> in no way provides rcu_read_lock()-style protection.
>>
>> Now, Alexei's question was for CONFIG_PREEMPT=n kernels. However, in
>> that case, rcu_read_lock() and rcu_read_unlock() generate no code
>> in recent production kernels, so there is no performance penalty for
>> using them. (In older kernels, they implied a barrier().)
>>
>> So either way, with or without CONFIG_PREEMPT, you should use
>> rcu_read_lock() to get RCU protection.
>>
>> One alternative might be to switch to rcu_read_lock_bh(), but that
>> will add local_disable_bh() overhead to your read paths.
>>
>> Does that help, or am I missing the point of the question?
>
> thanks a lot for explanation.
Glad you liked it!
> I mistakenly assumed that _bh variants are 'stronger' and
> act as inclusive, but sounds like they're completely orthogonal
> especially with preempt_rcu=y.
Yes, they are pretty much orthogonal.
> With preempt_rcu=n and preempt=y, it would be the case, since
> bh disables preemption and rcu_read_lock does the same as well,
> right? Of course, the code shouldn't be relying on that, so we
> have to fix our stuff.
Indeed, especially given that the kernel currently won't allow you
to configure CONFIG_PREEMPT_RCU=n and CONFIG_PREEMPT=y. If it does,
please let me know, as that would be a bug that needs to be fixed.
(For one thing, I do not test that combination.)
Thanx, Paul
And now, fast-forward again to 2021 ... :)
Thanks,
Daniel
Hi Paul,
On 6/10/21 8:38 PM, Alexei Starovoitov wrote:
quoted
On Wed, Jun 9, 2021 at 7:24 AM Toke Høiland-Jørgensen [off-list ref] wrote:
quoted
XDP programs are called from a NAPI poll context, which means the RCU
reference liveness is ensured by local_bh_disable(). Add
rcu_read_lock_bh_held() as a condition to the RCU checks for map lookups so
lockdep understands that the dereferences are safe from inside *either* an
rcu_read_lock() section *or* a local_bh_disable() section. This is done in
preparation for removing the redundant rcu_read_lock()s from the drivers.
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
kernel/bpf/hashtab.c | 21 ++++++++++++++-------
kernel/bpf/helpers.c | 6 +++---
kernel/bpf/lpm_trie.c | 6 ++++--
3 files changed, 21 insertions(+), 12 deletions(-)
It's not clear to me whether rcu_read_lock_held() is still needed.
All comments sound like rcu_read_lock_bh_held() is a superset of rcu
that includes bh.
But reading rcu source code it looks like RCU_BH is its own rcu flavor...
which is confusing.
The series is a bit confusing to me as well. I recall we had a discussion with
Paul, but it was back in 2016 aka very early days of XDP to get some clarifications
about RCU vs RCU-bh flavour on this. Paul, given the series in here, I assume the
below is not true anymore, and in this case (since we're removing rcu_read_lock()
from drivers), the RCU-bh acts as a real superset?
Back then from your clarifications this was not the case:
On Mon, Jul 25, 2016 at 11:26:02AM -0700, Alexei Starovoitov wrote:
> On Mon, Jul 25, 2016 at 11:03 AM, Paul E. McKenney
> [off-list ref] wrote:
[...]
>>> The crux of the question is whether a particular driver rx handler, when
>>> called from __do_softirq, needs to add an additional rcu_read_lock or
>>> whether it can rely on the mechanics of softirq.
>>
>> If it was rcu_read_lock_bh(), you could.
>>
>> But you didn't say rcu_read_lock_bh(), you instead said rcu_read_lock(),
>> which means that you absolutely cannot rely on softirq semantics.
>>
>> In particular, in CONFIG_PREEMPT=y kernels, rcu_preempt_check_callbacks()
>> will notice that there is no rcu_read_lock() in effect and report
>> a quiescent state for that CPU. Because rcu_preempt_check_callbacks()
>> is invoked from the scheduling-clock interrupt, it absolutely can
>> execute during do_softirq(), and therefore being in softirq context
>> in no way provides rcu_read_lock()-style protection.
>>
>> Now, Alexei's question was for CONFIG_PREEMPT=n kernels. However, in
>> that case, rcu_read_lock() and rcu_read_unlock() generate no code
>> in recent production kernels, so there is no performance penalty for
>> using them. (In older kernels, they implied a barrier().)
>>
>> So either way, with or without CONFIG_PREEMPT, you should use
>> rcu_read_lock() to get RCU protection.
>>
>> One alternative might be to switch to rcu_read_lock_bh(), but that
>> will add local_disable_bh() overhead to your read paths.
>>
>> Does that help, or am I missing the point of the question?
>
> thanks a lot for explanation.
Glad you liked it!
> I mistakenly assumed that _bh variants are 'stronger' and
> act as inclusive, but sounds like they're completely orthogonal
> especially with preempt_rcu=y.
Yes, they are pretty much orthogonal.
> With preempt_rcu=n and preempt=y, it would be the case, since
> bh disables preemption and rcu_read_lock does the same as well,
> right? Of course, the code shouldn't be relying on that, so we
> have to fix our stuff.
Indeed, especially given that the kernel currently won't allow you
to configure CONFIG_PREEMPT_RCU=n and CONFIG_PREEMPT=y. If it does,
please let me know, as that would be a bug that needs to be fixed.
(For one thing, I do not test that combination.)
Thanx, Paul
And now, fast-forward again to 2021 ... :)
On Wed, Jun 09, 2021 at 12:33:12PM +0200, Toke Høiland-Jørgensen wrote:
quoted
Some of the XDP helpers (in particular, xdp_do_redirect()) will get a
struct net_device reference using dev_get_by_index_rcu(). These are called
from a NAPI poll context, which means the RCU reference liveness is ensured
by local_bh_disable(). Add rcu_read_lock_bh_held() as a condition to the
RCU list traversal in dev_get_by_index_rcu() so lockdep understands that
the dereferences are safe from *both* an rcu_read_lock() *and* with
local_bh_disable().
Signed-off-by: Toke Høiland-Jørgensen <redacted>
---
net/core/dev.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
@@ -1002,7 +1002,7 @@ struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex)structnet_device*dev;structhlist_head*head=dev_index_hash(net,ifindex);-hlist_for_each_entry_rcu(dev,head,index_hlist)+hlist_for_each_entry_rcu(dev,head,index_hlist,rcu_read_lock_bh_held())
Is it needed? hlist_for_each_entry_rcu() checks for
rcu_read_lock_any_held(). Did lockdep complain?
Ah, yes, I think you're right. I totally missed that
rcu_read_lock_any_held() includes a '!preemptible()' check at the end.
I'll drop this patch, then!
-Toke
From: Simon Horman <hidden> Date: 2021-06-11 16:31:05
+Jakub
On Wed, Jun 09, 2021 at 12:33:21PM +0200, Toke Høiland-Jørgensen wrote:
The nfp driver has rcu_read_lock()/rcu_read_unlock() pairs around XDP
program invocations. However, the actual lifetime of the objects referred
by the XDP program invocation is longer, all the way through to the call to
xdp_do_flush(), making the scope of the rcu_read_lock() too small.
While this is not actually an issue for the nfp driver because it doesn't
support XDP_REDIRECT (and thus doesn't call xdp_do_flush()), the
rcu_read_lock() is still unneeded. And With the addition of RCU annotations
to the XDP_REDIRECT map types that take bh execution into account, lockdep
even understands this to be safe, so there's really no reason to keep it
around.
Cc: Simon Horman <redacted>
Cc: oss-drivers@netronome.com
Signed-off-by: Toke Høiland-Jørgensen <redacted>