Now that PPPoE sockets are freed via RCU (SOCK_RCU_FREE), it is no longer necessary to take a reference count when looking up sockets on the receive path. Readers are protected by RCU, so the socket memory remains valid until after a grace period. Convert fast-path lookups to avoid refcounting: - Replace get_item() and sk_receive_skb() in pppoe_rcv() with __get_item() and __sk_receive_skb(). - Rework get_item_by_addr() into __get_item_by_addr() (no refcount) and add check_item_by_addr() for existence checks in pppoe_ioctl(). - Remove unnecessary sock_put() calls. This avoids cacheline bouncing from atomic reference counting and improves performance on the receive fast path. Signed-off-by: Qingfang Deng --- drivers/net/ppp/pppoe.c | 54 +++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index f99533c80b66..70a7e1e88799 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -237,13 +237,30 @@ static inline struct pppox_sock *get_item(struct pppoe_net *pn, __be16 sid, return po; } -static inline struct pppox_sock *get_item_by_addr(struct net *net, - struct sockaddr_pppox *sp) +static inline struct pppox_sock *__get_item_by_addr(struct net *net, + struct sockaddr_pppox *sp) { struct net_device *dev; struct pppoe_net *pn; struct pppox_sock *pppox_sock = NULL; + int ifindex; + + dev = dev_get_by_name_rcu(net, sp->sa_addr.pppoe.dev); + if (dev) { + ifindex = dev->ifindex; + pn = pppoe_pernet(net); + pppox_sock = __get_item(pn, sp->sa_addr.pppoe.sid, + sp->sa_addr.pppoe.remote, ifindex); + } + return pppox_sock; +} +static inline bool check_item_by_addr(struct net *net, + struct sockaddr_pppox *sp) +{ + struct net_device *dev; + struct pppoe_net *pn; + bool ret = false; int ifindex; rcu_read_lock(); @@ -251,11 +268,11 @@ static inline struct pppox_sock *get_item_by_addr(struct net *net, if (dev) { ifindex = dev->ifindex; pn = pppoe_pernet(net); - pppox_sock = get_item(pn, sp->sa_addr.pppoe.sid, - sp->sa_addr.pppoe.remote, ifindex); + ret = !!__get_item(pn, sp->sa_addr.pppoe.sid, + sp->sa_addr.pppoe.remote, ifindex); } rcu_read_unlock(); - return pppox_sock; + return ret; } static inline void delete_item(struct pppoe_net *pn, __be16 sid, @@ -381,18 +398,16 @@ static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb) if (sk->sk_state & PPPOX_BOUND) { ppp_input(&po->chan, skb); } else if (sk->sk_state & PPPOX_RELAY) { - relay_po = get_item_by_addr(sock_net(sk), - &po->pppoe_relay); + relay_po = __get_item_by_addr(sock_net(sk), + &po->pppoe_relay); if (relay_po == NULL) goto abort_kfree; if ((sk_pppox(relay_po)->sk_state & PPPOX_CONNECTED) == 0) - goto abort_put; + goto abort_kfree; if (!__pppoe_xmit(sk_pppox(relay_po), skb)) - goto abort_put; - - sock_put(sk_pppox(relay_po)); + goto abort_kfree; } else { if (sock_queue_rcv_skb(sk, skb)) goto abort_kfree; @@ -400,9 +415,6 @@ static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb) return NET_RX_SUCCESS; -abort_put: - sock_put(sk_pppox(relay_po)); - abort_kfree: kfree_skb(skb); return NET_RX_DROP; @@ -447,14 +459,11 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev, ph = pppoe_hdr(skb); pn = pppoe_pernet(dev_net(dev)); - /* Note that get_item does a sock_hold(), so sk_pppox(po) - * is known to be safe. - */ - po = get_item(pn, ph->sid, eth_hdr(skb)->h_source, dev->ifindex); + po = __get_item(pn, ph->sid, eth_hdr(skb)->h_source, dev->ifindex); if (!po) goto drop; - return sk_receive_skb(sk_pppox(po), skb, 0); + return __sk_receive_skb(sk_pppox(po), skb, 0, 1, false); drop: kfree_skb(skb); @@ -790,7 +799,7 @@ static int pppoe_ioctl(struct socket *sock, unsigned int cmd, case PPPOEIOCSFWD: { - struct pppox_sock *relay_po; + bool ret; err = -EBUSY; if (sk->sk_state & (PPPOX_BOUND | PPPOX_DEAD)) @@ -815,11 +824,10 @@ static int pppoe_ioctl(struct socket *sock, unsigned int cmd, /* Check that the socket referenced by the address actually exists. */ - relay_po = get_item_by_addr(sock_net(sk), &po->pppoe_relay); - if (!relay_po) + ret = check_item_by_addr(sock_net(sk), &po->pppoe_relay); + if (!ret) break; - sock_put(sk_pppox(relay_po)); sk->sk_state |= PPPOX_RELAY; err = 0; break; -- 2.43.0