Skip to content

Commit

Permalink
net_failover: hold the netdev lists lock when retrieving device stati…
Browse files Browse the repository at this point in the history
…stics

In the effort of making .ndo_get_stats64 be able to sleep, we need to
ensure the callers of dev_get_stats do not use atomic context.

The net_failover driver makes copious abuse of RCU protection for the
slave interfaces, which is probably unnecessary given the fact that it
already calls dev_hold on slave interfaces. Nonetheless, to avoid
regressions, we still need to offer the same level of protection against
unregistering the standby and primary devices. We can achieve this by
holding the netns mutex, which gives us the sleepable context that
dev_get_stats() wants to see. Holding this mutex also removes the need
for a separate lock for statistics.

Cc: Sridhar Samudrala <sridhar.samudrala@intel.com>
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
  • Loading branch information
vladimiroltean authored and intel-lab-lkp committed Dec 7, 2020
1 parent 036daee commit 6ffc75e
Show file tree
Hide file tree
Showing 2 changed files with 7 additions and 11 deletions.
15 changes: 7 additions & 8 deletions drivers/net/net_failover.c
Original file line number Diff line number Diff line change
Expand Up @@ -184,32 +184,31 @@ static void net_failover_get_stats(struct net_device *dev,
{
struct net_failover_info *nfo_info = netdev_priv(dev);
const struct rtnl_link_stats64 *new;
struct net *net = dev_net(dev);
struct rtnl_link_stats64 temp;
struct net_device *slave_dev;

spin_lock(&nfo_info->stats_lock);
memcpy(stats, &nfo_info->failover_stats, sizeof(*stats));
mutex_lock(&net->netdev_lists_lock);

rcu_read_lock();
memcpy(stats, &nfo_info->failover_stats, sizeof(*stats));

slave_dev = rcu_dereference(nfo_info->primary_dev);
slave_dev = nfo_info->primary_dev;
if (slave_dev) {
new = dev_get_stats(slave_dev, &temp);
net_failover_fold_stats(stats, new, &nfo_info->primary_stats);
memcpy(&nfo_info->primary_stats, new, sizeof(*new));
}

slave_dev = rcu_dereference(nfo_info->standby_dev);
slave_dev = nfo_info->standby_dev;
if (slave_dev) {
new = dev_get_stats(slave_dev, &temp);
net_failover_fold_stats(stats, new, &nfo_info->standby_stats);
memcpy(&nfo_info->standby_stats, new, sizeof(*new));
}

rcu_read_unlock();

memcpy(&nfo_info->failover_stats, stats, sizeof(*stats));
spin_unlock(&nfo_info->stats_lock);

mutex_unlock(&net->netdev_lists_lock);
}

static int net_failover_change_mtu(struct net_device *dev, int new_mtu)
Expand Down
3 changes: 0 additions & 3 deletions include/net/net_failover.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ struct net_failover_info {

/* aggregated stats */
struct rtnl_link_stats64 failover_stats;

/* spinlock while updating stats */
spinlock_t stats_lock;
};

struct failover *net_failover_create(struct net_device *standby_dev);
Expand Down

0 comments on commit 6ffc75e

Please sign in to comment.