Skip to content

Commit

Permalink
Merge branch 'qualcomm-rmnet-Fix-issues-with-CONFIG_DEBUG_PREEMPT-ena…
Browse files Browse the repository at this point in the history
…bled'

Subash Abhinov Kasiviswanathan says:

====================
net: qualcomm: rmnet: Fix issues with CONFIG_DEBUG_PREEMPT enabled

Patch 1 and 2 fixes issues identified when CONFIG_DEBUG_PREEMPT was
enabled. These involve APIs which were called in invalid contexts.

Patch 3 is a null derefence fix identified by code inspection.
====================

Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
davem330 committed Feb 19, 2018
2 parents 9ab2323 + f57bbaa commit cae6925
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 55 deletions.
68 changes: 14 additions & 54 deletions drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,6 @@

/* Local Definitions and Declarations */

struct rmnet_walk_data {
struct net_device *real_dev;
struct list_head *head;
struct rmnet_port *port;
};

static int rmnet_is_real_dev_registered(const struct net_device *real_dev)
{
return rcu_access_pointer(real_dev->rx_handler) == rmnet_rx_handler;
Expand Down Expand Up @@ -112,17 +106,14 @@ static int rmnet_register_real_device(struct net_device *real_dev)
static void rmnet_unregister_bridge(struct net_device *dev,
struct rmnet_port *port)
{
struct net_device *rmnet_dev, *bridge_dev;
struct rmnet_port *bridge_port;
struct net_device *bridge_dev;

if (port->rmnet_mode != RMNET_EPMODE_BRIDGE)
return;

/* bridge slave handling */
if (!port->nr_rmnet_devs) {
rmnet_dev = netdev_master_upper_dev_get_rcu(dev);
netdev_upper_dev_unlink(dev, rmnet_dev);

bridge_dev = port->bridge_ep;

bridge_port = rmnet_get_port_rtnl(bridge_dev);
Expand All @@ -132,9 +123,6 @@ static void rmnet_unregister_bridge(struct net_device *dev,
bridge_dev = port->bridge_ep;

bridge_port = rmnet_get_port_rtnl(bridge_dev);
rmnet_dev = netdev_master_upper_dev_get_rcu(bridge_dev);
netdev_upper_dev_unlink(bridge_dev, rmnet_dev);

rmnet_unregister_real_device(bridge_dev, bridge_port);
}
}
Expand Down Expand Up @@ -173,10 +161,6 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,
if (err)
goto err1;

err = netdev_master_upper_dev_link(dev, real_dev, NULL, NULL, extack);
if (err)
goto err2;

port->rmnet_mode = mode;

hlist_add_head_rcu(&ep->hlnode, &port->muxed_ep[mux_id]);
Expand All @@ -193,8 +177,6 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,

return 0;

err2:
rmnet_vnd_dellink(mux_id, port, ep);
err1:
rmnet_unregister_real_device(real_dev, port);
err0:
Expand All @@ -204,22 +186,20 @@ static int rmnet_newlink(struct net *src_net, struct net_device *dev,

static void rmnet_dellink(struct net_device *dev, struct list_head *head)
{
struct rmnet_priv *priv = netdev_priv(dev);
struct net_device *real_dev;
struct rmnet_endpoint *ep;
struct rmnet_port *port;
u8 mux_id;

rcu_read_lock();
real_dev = netdev_master_upper_dev_get_rcu(dev);
rcu_read_unlock();
real_dev = priv->real_dev;

if (!real_dev || !rmnet_is_real_dev_registered(real_dev))
return;

port = rmnet_get_port_rtnl(real_dev);

mux_id = rmnet_vnd_get_mux(dev);
netdev_upper_dev_unlink(dev, real_dev);

ep = rmnet_get_endpoint(port, mux_id);
if (ep) {
Expand All @@ -233,47 +213,33 @@ static void rmnet_dellink(struct net_device *dev, struct list_head *head)
unregister_netdevice_queue(dev, head);
}

static int rmnet_dev_walk_unreg(struct net_device *rmnet_dev, void *data)
{
struct rmnet_walk_data *d = data;
struct rmnet_endpoint *ep;
u8 mux_id;

mux_id = rmnet_vnd_get_mux(rmnet_dev);
ep = rmnet_get_endpoint(d->port, mux_id);
if (ep) {
hlist_del_init_rcu(&ep->hlnode);
rmnet_vnd_dellink(mux_id, d->port, ep);
kfree(ep);
}
netdev_upper_dev_unlink(rmnet_dev, d->real_dev);
unregister_netdevice_queue(rmnet_dev, d->head);

return 0;
}

static void rmnet_force_unassociate_device(struct net_device *dev)
{
struct net_device *real_dev = dev;
struct rmnet_walk_data d;
struct hlist_node *tmp_ep;
struct rmnet_endpoint *ep;
struct rmnet_port *port;
unsigned long bkt_ep;
LIST_HEAD(list);

if (!rmnet_is_real_dev_registered(real_dev))
return;

ASSERT_RTNL();

d.real_dev = real_dev;
d.head = &list;

port = rmnet_get_port_rtnl(dev);
d.port = port;

rcu_read_lock();
rmnet_unregister_bridge(dev, port);

netdev_walk_all_lower_dev_rcu(real_dev, rmnet_dev_walk_unreg, &d);
hash_for_each_safe(port->muxed_ep, bkt_ep, tmp_ep, ep, hlnode) {
unregister_netdevice_queue(ep->egress_dev, &list);
rmnet_vnd_dellink(ep->mux_id, port, ep);

hlist_del_init_rcu(&ep->hlnode);
kfree(ep);
}

rcu_read_unlock();
unregister_netdevice_many(&list);

Expand Down Expand Up @@ -422,11 +388,6 @@ int rmnet_add_bridge(struct net_device *rmnet_dev,
if (err)
return -EBUSY;

err = netdev_master_upper_dev_link(slave_dev, rmnet_dev, NULL, NULL,
extack);
if (err)
return -EINVAL;

slave_port = rmnet_get_port(slave_dev);
slave_port->rmnet_mode = RMNET_EPMODE_BRIDGE;
slave_port->bridge_ep = real_dev;
Expand All @@ -449,7 +410,6 @@ int rmnet_del_bridge(struct net_device *rmnet_dev,
port->rmnet_mode = RMNET_EPMODE_VND;
port->bridge_ep = NULL;

netdev_upper_dev_unlink(slave_dev, rmnet_dev);
slave_port = rmnet_get_port(slave_dev);
rmnet_unregister_real_device(slave_dev, slave_port);

Expand Down
5 changes: 5 additions & 0 deletions drivers/net/ethernet/qualcomm/rmnet/rmnet_map_command.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ static u8 rmnet_map_do_flow_control(struct sk_buff *skb,
}

ep = rmnet_get_endpoint(port, mux_id);
if (!ep) {
kfree_skb(skb);
return RX_HANDLER_CONSUMED;
}

vnd = ep->egress_dev;

ip_family = cmd->flow_control.ip_family;
Expand Down
2 changes: 1 addition & 1 deletion drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ static void rmnet_get_stats64(struct net_device *dev,
memset(&total_stats, 0, sizeof(struct rmnet_vnd_stats));

for_each_possible_cpu(cpu) {
pcpu_ptr = this_cpu_ptr(priv->pcpu_stats);
pcpu_ptr = per_cpu_ptr(priv->pcpu_stats, cpu);

do {
start = u64_stats_fetch_begin_irq(&pcpu_ptr->syncp);
Expand Down

0 comments on commit cae6925

Please sign in to comment.