with attempt to reduce skb redistribution. Signed-off-by: Oleksij Rempel <o.rempel@xxxxxxxxxxxxxx> --- net/can/j1939/j1939-priv.h | 5 +++- net/can/j1939/main.c | 4 ++- net/can/j1939/socket.c | 59 ++++++++++++++++---------------------- net/can/j1939/transport.c | 3 +- 4 files changed, 34 insertions(+), 37 deletions(-) diff --git a/net/can/j1939/j1939-priv.h b/net/can/j1939/j1939-priv.h index dd9c513396e6..9e62e63aafbb 100644 --- a/net/can/j1939/j1939-priv.h +++ b/net/can/j1939/j1939-priv.h @@ -64,6 +64,9 @@ struct j1939_priv { struct list_head tp_extsessionq; wait_queue_head_t tp_wait; unsigned int tp_max_packet_size; + + struct list_head j1939_socks; + spinlock_t j1939_socks_lock; }; void j1939_ecu_put(struct j1939_ecu *ecu); @@ -150,7 +153,7 @@ static inline struct j1939_sk_buff_cb *j1939_skb_to_cb(struct sk_buff *skb) } int j1939_send_one(struct j1939_priv *priv, struct sk_buff *skb); -void j1939_sk_recv(struct sk_buff *skb); +void j1939_sk_recv(struct j1939_priv *priv, struct sk_buff *skb); /* stack entries */ struct j1939_session *j1939_tp_send(struct j1939_priv *priv, diff --git a/net/can/j1939/main.c b/net/can/j1939/main.c index 13ac2661625c..11b63015b4f0 100644 --- a/net/can/j1939/main.c +++ b/net/can/j1939/main.c @@ -88,7 +88,7 @@ static void j1939_can_recv(struct sk_buff *iskb, void *data) if (j1939_tp_recv(priv, skb)) /* this means the transport layer processed the message */ goto done; - j1939_sk_recv(skb); + j1939_sk_recv(priv, skb); done: kfree_skb(skb); } @@ -170,6 +170,8 @@ int j1939_netdev_start(struct net *net, struct net_device *ndev) return -ENOMEM; j1939_tp_init(priv); + spin_lock_init(&priv->j1939_socks_lock); + INIT_LIST_HEAD(&priv->j1939_socks); /* add CAN handler */ ret = can_rx_register(net, ndev, J1939_CAN_ID, J1939_CAN_MASK, diff --git a/net/can/j1939/socket.c b/net/can/j1939/socket.c index 155af82f5b3a..c1ee5fa7b6f7 100644 --- a/net/can/j1939/socket.c +++ b/net/can/j1939/socket.c @@ -15,10 +15,6 @@ #define J1939_MIN_NAMELEN REQUIRED_SIZE(struct sockaddr_can, can_addr.j1939) -/* list of sockets */ -static struct list_head j1939_socks = LIST_HEAD_INIT(j1939_socks); -static DEFINE_SPINLOCK(j1939_socks_lock); - struct j1939_sock { struct sock sk; /* must be first to skip with memset */ struct list_head list; @@ -197,15 +193,15 @@ static void j1939_sk_recv_one(struct j1939_sock *jsk, struct sk_buff *oskb) kfree_skb(skb); } -void j1939_sk_recv(struct sk_buff *skb) +void j1939_sk_recv(struct j1939_priv *priv, struct sk_buff *skb) { struct j1939_sock *jsk; - spin_lock_bh(&j1939_socks_lock); - list_for_each_entry(jsk, &j1939_socks, list) { + spin_lock_bh(&priv->j1939_socks_lock); + list_for_each_entry(jsk, &priv->j1939_socks, list) { j1939_sk_recv_one(jsk, skb); } - spin_unlock_bh(&j1939_socks_lock); + spin_unlock_bh(&priv->j1939_socks_lock); } static int j1939_sk_init(struct sock *sk) @@ -297,19 +293,19 @@ static int j1939_sk_bind(struct socket *sock, struct sockaddr *uaddr, int len) /* get new references */ ret = j1939_local_ecu_get(priv, jsk->addr.src_name, jsk->addr.sa); - j1939_priv_put(priv); if (ret) { j1939_netdev_stop(ndev); goto out_dev_put; } if (!(jsk->state & J1939_SOCK_BOUND)) { - spin_lock_bh(&j1939_socks_lock); - list_add_tail(&jsk->list, &j1939_socks); - spin_unlock_bh(&j1939_socks_lock); + spin_lock_bh(&priv->j1939_socks_lock); + list_add_tail(&jsk->list, &priv->j1939_socks); + spin_unlock_bh(&priv->j1939_socks_lock); jsk->state |= J1939_SOCK_BOUND; } + j1939_priv_put(priv); out_dev_put: /* fallthrough */ dev_put(ndev); @@ -400,7 +396,6 @@ static int j1939_sk_release(struct socket *sock) { struct sock *sk = sock->sk; struct j1939_sock *jsk; - struct j1939_priv *priv; if (!sk) return 0; @@ -409,25 +404,25 @@ static int j1939_sk_release(struct socket *sock) lock_sock(sk); if (jsk->state & J1939_SOCK_BOUND) { + struct j1939_priv *priv; struct net_device *ndev; wait_event_interruptible(jsk->waitq, j1939_sock_pending_get(&jsk->sk) == 0); - spin_lock_bh(&j1939_socks_lock); + ndev = dev_get_by_index(sock_net(sk), jsk->ifindex); + priv = j1939_priv_get_by_ndev(ndev); + + spin_lock_bh(&priv->j1939_socks_lock); list_del_init(&jsk->list); - spin_unlock_bh(&j1939_socks_lock); + spin_unlock_bh(&priv->j1939_socks_lock); - ndev = dev_get_by_index(sock_net(sk), jsk->ifindex); - if (ndev) { - priv = j1939_priv_get_by_ndev(ndev); - j1939_local_ecu_put(priv, jsk->addr.src_name, + j1939_local_ecu_put(priv, jsk->addr.src_name, jsk->addr.sa); - j1939_priv_put(priv); + j1939_priv_put(priv); - j1939_netdev_stop(ndev); - dev_put(ndev); - } + j1939_netdev_stop(ndev); + dev_put(ndev); } sock_orphan(sk); @@ -484,11 +479,11 @@ static int j1939_sk_setsockopt(struct socket *sock, int level, int optname, return PTR_ERR(filters); } - spin_lock_bh(&j1939_socks_lock); + lock_sock(&jsk->sk); ofilters = jsk->filters; jsk->filters = filters; jsk->nfilters = count; - spin_unlock_bh(&j1939_socks_lock); + release_sock(&jsk->sk); kfree(ofilters); return 0; case SO_J1939_PROMISC: @@ -817,30 +812,26 @@ static int j1939_sk_sendmsg(struct socket *sock, struct msghdr *msg, void j1939_sk_netdev_event(struct net_device *ndev, int error_code) { + struct j1939_priv *priv = j1939_priv_get_by_ndev(ndev); struct j1939_sock *jsk; - spin_lock_bh(&j1939_socks_lock); - list_for_each_entry(jsk, &j1939_socks, list) { - if (jsk->ifindex != ndev->ifindex) - continue; + spin_lock_bh(&priv->j1939_socks_lock); + list_for_each_entry(jsk, &priv->j1939_socks, list) { jsk->sk.sk_err = error_code; if (!sock_flag(&jsk->sk, SOCK_DEAD)) jsk->sk.sk_error_report(&jsk->sk); if (error_code == ENODEV) { - struct j1939_priv *priv; - - priv = j1939_priv_get_by_ndev(ndev); j1939_local_ecu_put(priv, jsk->addr.src_name, jsk->addr.sa); - j1939_priv_put(priv); j1939_netdev_stop(ndev); } /* do not remove filters here */ } - spin_unlock_bh(&j1939_socks_lock); + spin_unlock_bh(&priv->j1939_socks_lock); + j1939_priv_put(priv); } static const struct proto_ops j1939_ops = { diff --git a/net/can/j1939/transport.c b/net/can/j1939/transport.c index b17c7e8573a1..dec4e8749805 100644 --- a/net/can/j1939/transport.c +++ b/net/can/j1939/transport.c @@ -697,8 +697,9 @@ static void __j1939_session_drop(struct j1939_session *session) static void j1939_session_completed(struct j1939_session *session) { struct sk_buff *se_skb = j1939_session_skb_find(session); + /* distribute among j1939 receivers */ - j1939_sk_recv(se_skb); + j1939_sk_recv(session->priv, se_skb); __j1939_session_drop(session); } -- 2.19.1