diff options
author | Edward Cree <ecree@solarflare.com> | 2018-03-27 18:44:36 +0200 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-03-27 19:33:20 +0200 |
commit | e0a65e3c5e3b7b11ec9320524b8fcc210f2026e9 (patch) | |
tree | e82d5fb1d37ef7bff0c1d75a2cbe1f7f0ede3e57 /drivers/net/ethernet/sfc/ethtool.c | |
parent | sfc: return a better error if filter insertion collides with MC reboot (diff) | |
download | linux-e0a65e3c5e3b7b11ec9320524b8fcc210f2026e9.tar.xz linux-e0a65e3c5e3b7b11ec9320524b8fcc210f2026e9.zip |
sfc: protect list of RSS contexts under a mutex
Otherwise races are possible between ethtool ops and
efx_ef10_rx_restore_rss_contexts().
Also, don't try to perform the restore on every reset, only after an MC
reboot, otherwise we'll leak RSS contexts on the NIC.
Fixes: 42356d9a137b ("sfc: support RSS spreading of ethtool ntuple filters")
Signed-off-by: Edward Cree <ecree@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/sfc/ethtool.c')
-rw-r--r-- | drivers/net/ethernet/sfc/ethtool.c | 66 |
1 files changed, 43 insertions, 23 deletions
diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index bb1c80d48d12..e07c8bc8f4bd 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c @@ -979,7 +979,7 @@ efx_ethtool_get_rxnfc(struct net_device *net_dev, { struct efx_nic *efx = netdev_priv(net_dev); u32 rss_context = 0; - s32 rc; + s32 rc = 0; switch (info->cmd) { case ETHTOOL_GRXRINGS: @@ -989,15 +989,17 @@ efx_ethtool_get_rxnfc(struct net_device *net_dev, case ETHTOOL_GRXFH: { struct efx_rss_context *ctx = &efx->rss_context; + mutex_lock(&efx->rss_lock); if (info->flow_type & FLOW_RSS && info->rss_context) { - ctx = efx_find_rss_context_entry(info->rss_context, - &efx->rss_context.list); - if (!ctx) - return -ENOENT; + ctx = efx_find_rss_context_entry(efx, info->rss_context); + if (!ctx) { + rc = -ENOENT; + goto out_unlock; + } } info->data = 0; if (!efx_rss_active(ctx)) /* No RSS */ - return 0; + goto out_unlock; switch (info->flow_type & ~FLOW_RSS) { case UDP_V4_FLOW: if (ctx->rx_hash_udp_4tuple) @@ -1024,7 +1026,9 @@ efx_ethtool_get_rxnfc(struct net_device *net_dev, default: break; } - return 0; +out_unlock: + mutex_unlock(&efx->rss_lock); + return rc; } case ETHTOOL_GRXCLSRLCNT: @@ -1366,16 +1370,20 @@ static int efx_ethtool_get_rxfh_context(struct net_device *net_dev, u32 *indir, { struct efx_nic *efx = netdev_priv(net_dev); struct efx_rss_context *ctx; - int rc; + int rc = 0; if (!efx->type->rx_pull_rss_context_config) return -EOPNOTSUPP; - ctx = efx_find_rss_context_entry(rss_context, &efx->rss_context.list); - if (!ctx) - return -ENOENT; + + mutex_lock(&efx->rss_lock); + ctx = efx_find_rss_context_entry(efx, rss_context); + if (!ctx) { + rc = -ENOENT; + goto out_unlock; + } rc = efx->type->rx_pull_rss_context_config(efx, ctx); if (rc) - return rc; + goto out_unlock; if (hfunc) *hfunc = ETH_RSS_HASH_TOP; @@ -1383,7 +1391,9 @@ static int efx_ethtool_get_rxfh_context(struct net_device *net_dev, u32 *indir, memcpy(indir, ctx->rx_indir_table, sizeof(ctx->rx_indir_table)); if (key) memcpy(key, ctx->rx_hash_key, efx->type->rx_hash_key_size); - return 0; +out_unlock: + mutex_unlock(&efx->rss_lock); + return rc; } static int efx_ethtool_set_rxfh_context(struct net_device *net_dev, @@ -1401,23 +1411,31 @@ static int efx_ethtool_set_rxfh_context(struct net_device *net_dev, /* Hash function is Toeplitz, cannot be changed */ if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) return -EOPNOTSUPP; + + mutex_lock(&efx->rss_lock); + if (*rss_context == ETH_RXFH_CONTEXT_ALLOC) { - if (delete) + if (delete) { /* alloc + delete == Nothing to do */ - return -EINVAL; - ctx = efx_alloc_rss_context_entry(&efx->rss_context.list); - if (!ctx) - return -ENOMEM; + rc = -EINVAL; + goto out_unlock; + } + ctx = efx_alloc_rss_context_entry(efx); + if (!ctx) { + rc = -ENOMEM; + goto out_unlock; + } ctx->context_id = EFX_EF10_RSS_CONTEXT_INVALID; /* Initialise indir table and key to defaults */ efx_set_default_rx_indir_table(efx, ctx); netdev_rss_key_fill(ctx->rx_hash_key, sizeof(ctx->rx_hash_key)); allocated = true; } else { - ctx = efx_find_rss_context_entry(*rss_context, - &efx->rss_context.list); - if (!ctx) - return -ENOENT; + ctx = efx_find_rss_context_entry(efx, *rss_context); + if (!ctx) { + rc = -ENOENT; + goto out_unlock; + } } if (delete) { @@ -1425,7 +1443,7 @@ static int efx_ethtool_set_rxfh_context(struct net_device *net_dev, rc = efx->type->rx_push_rss_context_config(efx, ctx, NULL, NULL); if (!rc) efx_free_rss_context_entry(ctx); - return rc; + goto out_unlock; } if (!key) @@ -1438,6 +1456,8 @@ static int efx_ethtool_set_rxfh_context(struct net_device *net_dev, efx_free_rss_context_entry(ctx); else *rss_context = ctx->user_id; +out_unlock: + mutex_unlock(&efx->rss_lock); return rc; } |