Skip to content

Commit e0a65e3

Browse files
ecree-solarflaredavem330
authored andcommitted
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: 42356d9 ("sfc: support RSS spreading of ethtool ntuple filters") Signed-off-by: Edward Cree <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 31b8429 commit e0a65e3

File tree

6 files changed

+89
-32
lines changed

6 files changed

+89
-32
lines changed

drivers/net/ethernet/sfc/ef10.c

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1499,6 +1499,7 @@ static void efx_ef10_reset_mc_allocations(struct efx_nic *efx)
14991499

15001500
/* All our allocations have been reset */
15011501
nic_data->must_realloc_vis = true;
1502+
nic_data->must_restore_rss_contexts = true;
15021503
nic_data->must_restore_filters = true;
15031504
nic_data->must_restore_piobufs = true;
15041505
efx_ef10_forget_old_piobufs(efx);
@@ -2899,6 +2900,8 @@ static int efx_ef10_rx_push_rss_context_config(struct efx_nic *efx,
28992900
{
29002901
int rc;
29012902

2903+
WARN_ON(!mutex_is_locked(&efx->rss_lock));
2904+
29022905
if (ctx->context_id == EFX_EF10_RSS_CONTEXT_INVALID) {
29032906
rc = efx_ef10_alloc_rss_context(efx, true, ctx, NULL);
29042907
if (rc)
@@ -2929,6 +2932,8 @@ static int efx_ef10_rx_pull_rss_context_config(struct efx_nic *efx,
29292932
size_t outlen;
29302933
int rc, i;
29312934

2935+
WARN_ON(!mutex_is_locked(&efx->rss_lock));
2936+
29322937
BUILD_BUG_ON(MC_CMD_RSS_CONTEXT_GET_TABLE_IN_LEN !=
29332938
MC_CMD_RSS_CONTEXT_GET_KEY_IN_LEN);
29342939

@@ -2972,14 +2977,25 @@ static int efx_ef10_rx_pull_rss_context_config(struct efx_nic *efx,
29722977

29732978
static int efx_ef10_rx_pull_rss_config(struct efx_nic *efx)
29742979
{
2975-
return efx_ef10_rx_pull_rss_context_config(efx, &efx->rss_context);
2980+
int rc;
2981+
2982+
mutex_lock(&efx->rss_lock);
2983+
rc = efx_ef10_rx_pull_rss_context_config(efx, &efx->rss_context);
2984+
mutex_unlock(&efx->rss_lock);
2985+
return rc;
29762986
}
29772987

29782988
static void efx_ef10_rx_restore_rss_contexts(struct efx_nic *efx)
29792989
{
2990+
struct efx_ef10_nic_data *nic_data = efx->nic_data;
29802991
struct efx_rss_context *ctx;
29812992
int rc;
29822993

2994+
WARN_ON(!mutex_is_locked(&efx->rss_lock));
2995+
2996+
if (!nic_data->must_restore_rss_contexts)
2997+
return;
2998+
29832999
list_for_each_entry(ctx, &efx->rss_context.list, list) {
29843000
/* previous NIC RSS context is gone */
29853001
ctx->context_id = EFX_EF10_RSS_CONTEXT_INVALID;
@@ -2993,6 +3009,7 @@ static void efx_ef10_rx_restore_rss_contexts(struct efx_nic *efx)
29933009
"; RSS filters may fail to be applied\n",
29943010
ctx->user_id, rc);
29953011
}
3012+
nic_data->must_restore_rss_contexts = false;
29963013
}
29973014

29983015
static int efx_ef10_pf_rx_push_rss_config(struct efx_nic *efx, bool user,
@@ -4307,6 +4324,7 @@ static s32 efx_ef10_filter_insert(struct efx_nic *efx,
43074324
struct efx_rss_context *ctx = NULL;
43084325
unsigned int match_pri, hash;
43094326
unsigned int priv_flags;
4327+
bool rss_locked = false;
43104328
bool replacing = false;
43114329
unsigned int depth, i;
43124330
int ins_index = -1;
@@ -4336,9 +4354,10 @@ static s32 efx_ef10_filter_insert(struct efx_nic *efx,
43364354
bitmap_zero(mc_rem_map, EFX_EF10_FILTER_SEARCH_LIMIT);
43374355

43384356
if (spec->flags & EFX_FILTER_FLAG_RX_RSS) {
4357+
mutex_lock(&efx->rss_lock);
4358+
rss_locked = true;
43394359
if (spec->rss_context)
4340-
ctx = efx_find_rss_context_entry(spec->rss_context,
4341-
&efx->rss_context.list);
4360+
ctx = efx_find_rss_context_entry(efx, spec->rss_context);
43424361
else
43434362
ctx = &efx->rss_context;
43444363
if (!ctx) {
@@ -4501,6 +4520,8 @@ static s32 efx_ef10_filter_insert(struct efx_nic *efx,
45014520
rc = efx_ef10_make_filter_id(match_pri, ins_index);
45024521

45034522
out_unlock:
4523+
if (rss_locked)
4524+
mutex_unlock(&efx->rss_lock);
45044525
up_write(&table->lock);
45054526
up_read(&efx->filter_sem);
45064527
return rc;
@@ -5008,6 +5029,7 @@ static void efx_ef10_filter_table_restore(struct efx_nic *efx)
50085029
return;
50095030

50105031
down_write(&table->lock);
5032+
mutex_lock(&efx->rss_lock);
50115033

50125034
for (filter_idx = 0; filter_idx < HUNT_FILTER_TBL_ROWS; filter_idx++) {
50135035
spec = efx_ef10_filter_entry_spec(table, filter_idx);
@@ -5024,8 +5046,7 @@ static void efx_ef10_filter_table_restore(struct efx_nic *efx)
50245046
goto not_restored;
50255047
}
50265048
if (spec->rss_context)
5027-
ctx = efx_find_rss_context_entry(spec->rss_context,
5028-
&efx->rss_context.list);
5049+
ctx = efx_find_rss_context_entry(efx, spec->rss_context);
50295050
else
50305051
ctx = &efx->rss_context;
50315052
if (spec->flags & EFX_FILTER_FLAG_RX_RSS) {
@@ -5064,6 +5085,7 @@ static void efx_ef10_filter_table_restore(struct efx_nic *efx)
50645085
}
50655086
}
50665087

5088+
mutex_unlock(&efx->rss_lock);
50675089
up_write(&table->lock);
50685090

50695091
/* This can happen validly if the MC's capabilities have changed, so

drivers/net/ethernet/sfc/efx.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2657,6 +2657,7 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method)
26572657
efx_disable_interrupts(efx);
26582658

26592659
mutex_lock(&efx->mac_lock);
2660+
mutex_lock(&efx->rss_lock);
26602661
if (efx->port_initialized && method != RESET_TYPE_INVISIBLE &&
26612662
method != RESET_TYPE_DATAPATH)
26622663
efx->phy_op->fini(efx);
@@ -2712,6 +2713,7 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
27122713

27132714
if (efx->type->rx_restore_rss_contexts)
27142715
efx->type->rx_restore_rss_contexts(efx);
2716+
mutex_unlock(&efx->rss_lock);
27152717
down_read(&efx->filter_sem);
27162718
efx_restore_filters(efx);
27172719
up_read(&efx->filter_sem);
@@ -2730,6 +2732,7 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
27302732
fail:
27312733
efx->port_initialized = false;
27322734

2735+
mutex_unlock(&efx->rss_lock);
27332736
mutex_unlock(&efx->mac_lock);
27342737

27352738
return rc;
@@ -3016,6 +3019,7 @@ static int efx_init_struct(struct efx_nic *efx,
30163019
efx->rx_packet_ts_offset =
30173020
efx->type->rx_ts_offset - efx->type->rx_prefix_size;
30183021
INIT_LIST_HEAD(&efx->rss_context.list);
3022+
mutex_init(&efx->rss_lock);
30193023
spin_lock_init(&efx->stats_lock);
30203024
efx->vi_stride = EFX_DEFAULT_VI_STRIDE;
30213025
efx->num_mac_stats = MC_CMD_MAC_NSTATS;
@@ -3091,11 +3095,14 @@ void efx_update_sw_stats(struct efx_nic *efx, u64 *stats)
30913095
/* RSS contexts. We're using linked lists and crappy O(n) algorithms, because
30923096
* (a) this is an infrequent control-plane operation and (b) n is small (max 64)
30933097
*/
3094-
struct efx_rss_context *efx_alloc_rss_context_entry(struct list_head *head)
3098+
struct efx_rss_context *efx_alloc_rss_context_entry(struct efx_nic *efx)
30953099
{
3100+
struct list_head *head = &efx->rss_context.list;
30963101
struct efx_rss_context *ctx, *new;
30973102
u32 id = 1; /* Don't use zero, that refers to the master RSS context */
30983103

3104+
WARN_ON(!mutex_is_locked(&efx->rss_lock));
3105+
30993106
/* Search for first gap in the numbering */
31003107
list_for_each_entry(ctx, head, list) {
31013108
if (ctx->user_id != id)
@@ -3121,10 +3128,13 @@ struct efx_rss_context *efx_alloc_rss_context_entry(struct list_head *head)
31213128
return new;
31223129
}
31233130

3124-
struct efx_rss_context *efx_find_rss_context_entry(u32 id, struct list_head *head)
3131+
struct efx_rss_context *efx_find_rss_context_entry(struct efx_nic *efx, u32 id)
31253132
{
3133+
struct list_head *head = &efx->rss_context.list;
31263134
struct efx_rss_context *ctx;
31273135

3136+
WARN_ON(!mutex_is_locked(&efx->rss_lock));
3137+
31283138
list_for_each_entry(ctx, head, list)
31293139
if (ctx->user_id == id)
31303140
return ctx;

drivers/net/ethernet/sfc/efx.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -187,8 +187,8 @@ static inline void efx_filter_rfs_expire(struct work_struct *data) {}
187187
bool efx_filter_is_mc_recipient(const struct efx_filter_spec *spec);
188188

189189
/* RSS contexts */
190-
struct efx_rss_context *efx_alloc_rss_context_entry(struct list_head *list);
191-
struct efx_rss_context *efx_find_rss_context_entry(u32 id, struct list_head *list);
190+
struct efx_rss_context *efx_alloc_rss_context_entry(struct efx_nic *efx);
191+
struct efx_rss_context *efx_find_rss_context_entry(struct efx_nic *efx, u32 id);
192192
void efx_free_rss_context_entry(struct efx_rss_context *ctx);
193193
static inline bool efx_rss_active(struct efx_rss_context *ctx)
194194
{

drivers/net/ethernet/sfc/ethtool.c

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -979,7 +979,7 @@ efx_ethtool_get_rxnfc(struct net_device *net_dev,
979979
{
980980
struct efx_nic *efx = netdev_priv(net_dev);
981981
u32 rss_context = 0;
982-
s32 rc;
982+
s32 rc = 0;
983983

984984
switch (info->cmd) {
985985
case ETHTOOL_GRXRINGS:
@@ -989,15 +989,17 @@ efx_ethtool_get_rxnfc(struct net_device *net_dev,
989989
case ETHTOOL_GRXFH: {
990990
struct efx_rss_context *ctx = &efx->rss_context;
991991

992+
mutex_lock(&efx->rss_lock);
992993
if (info->flow_type & FLOW_RSS && info->rss_context) {
993-
ctx = efx_find_rss_context_entry(info->rss_context,
994-
&efx->rss_context.list);
995-
if (!ctx)
996-
return -ENOENT;
994+
ctx = efx_find_rss_context_entry(efx, info->rss_context);
995+
if (!ctx) {
996+
rc = -ENOENT;
997+
goto out_unlock;
998+
}
997999
}
9981000
info->data = 0;
9991001
if (!efx_rss_active(ctx)) /* No RSS */
1000-
return 0;
1002+
goto out_unlock;
10011003
switch (info->flow_type & ~FLOW_RSS) {
10021004
case UDP_V4_FLOW:
10031005
if (ctx->rx_hash_udp_4tuple)
@@ -1024,7 +1026,9 @@ efx_ethtool_get_rxnfc(struct net_device *net_dev,
10241026
default:
10251027
break;
10261028
}
1027-
return 0;
1029+
out_unlock:
1030+
mutex_unlock(&efx->rss_lock);
1031+
return rc;
10281032
}
10291033

10301034
case ETHTOOL_GRXCLSRLCNT:
@@ -1366,24 +1370,30 @@ static int efx_ethtool_get_rxfh_context(struct net_device *net_dev, u32 *indir,
13661370
{
13671371
struct efx_nic *efx = netdev_priv(net_dev);
13681372
struct efx_rss_context *ctx;
1369-
int rc;
1373+
int rc = 0;
13701374

13711375
if (!efx->type->rx_pull_rss_context_config)
13721376
return -EOPNOTSUPP;
1373-
ctx = efx_find_rss_context_entry(rss_context, &efx->rss_context.list);
1374-
if (!ctx)
1375-
return -ENOENT;
1377+
1378+
mutex_lock(&efx->rss_lock);
1379+
ctx = efx_find_rss_context_entry(efx, rss_context);
1380+
if (!ctx) {
1381+
rc = -ENOENT;
1382+
goto out_unlock;
1383+
}
13761384
rc = efx->type->rx_pull_rss_context_config(efx, ctx);
13771385
if (rc)
1378-
return rc;
1386+
goto out_unlock;
13791387

13801388
if (hfunc)
13811389
*hfunc = ETH_RSS_HASH_TOP;
13821390
if (indir)
13831391
memcpy(indir, ctx->rx_indir_table, sizeof(ctx->rx_indir_table));
13841392
if (key)
13851393
memcpy(key, ctx->rx_hash_key, efx->type->rx_hash_key_size);
1386-
return 0;
1394+
out_unlock:
1395+
mutex_unlock(&efx->rss_lock);
1396+
return rc;
13871397
}
13881398

13891399
static int efx_ethtool_set_rxfh_context(struct net_device *net_dev,
@@ -1401,31 +1411,39 @@ static int efx_ethtool_set_rxfh_context(struct net_device *net_dev,
14011411
/* Hash function is Toeplitz, cannot be changed */
14021412
if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
14031413
return -EOPNOTSUPP;
1414+
1415+
mutex_lock(&efx->rss_lock);
1416+
14041417
if (*rss_context == ETH_RXFH_CONTEXT_ALLOC) {
1405-
if (delete)
1418+
if (delete) {
14061419
/* alloc + delete == Nothing to do */
1407-
return -EINVAL;
1408-
ctx = efx_alloc_rss_context_entry(&efx->rss_context.list);
1409-
if (!ctx)
1410-
return -ENOMEM;
1420+
rc = -EINVAL;
1421+
goto out_unlock;
1422+
}
1423+
ctx = efx_alloc_rss_context_entry(efx);
1424+
if (!ctx) {
1425+
rc = -ENOMEM;
1426+
goto out_unlock;
1427+
}
14111428
ctx->context_id = EFX_EF10_RSS_CONTEXT_INVALID;
14121429
/* Initialise indir table and key to defaults */
14131430
efx_set_default_rx_indir_table(efx, ctx);
14141431
netdev_rss_key_fill(ctx->rx_hash_key, sizeof(ctx->rx_hash_key));
14151432
allocated = true;
14161433
} else {
1417-
ctx = efx_find_rss_context_entry(*rss_context,
1418-
&efx->rss_context.list);
1419-
if (!ctx)
1420-
return -ENOENT;
1434+
ctx = efx_find_rss_context_entry(efx, *rss_context);
1435+
if (!ctx) {
1436+
rc = -ENOENT;
1437+
goto out_unlock;
1438+
}
14211439
}
14221440

14231441
if (delete) {
14241442
/* delete this context */
14251443
rc = efx->type->rx_push_rss_context_config(efx, ctx, NULL, NULL);
14261444
if (!rc)
14271445
efx_free_rss_context_entry(ctx);
1428-
return rc;
1446+
goto out_unlock;
14291447
}
14301448

14311449
if (!key)
@@ -1438,6 +1456,8 @@ static int efx_ethtool_set_rxfh_context(struct net_device *net_dev,
14381456
efx_free_rss_context_entry(ctx);
14391457
else
14401458
*rss_context = ctx->user_id;
1459+
out_unlock:
1460+
mutex_unlock(&efx->rss_lock);
14411461
return rc;
14421462
}
14431463

drivers/net/ethernet/sfc/net_driver.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,7 @@ struct efx_rss_context {
796796
* @rx_scatter: Scatter mode enabled for receives
797797
* @rss_context: Main RSS context. Its @list member is the head of the list of
798798
* RSS contexts created by user requests
799+
* @rss_lock: Protects custom RSS context software state in @rss_context.list
799800
* @int_error_count: Number of internal errors seen recently
800801
* @int_error_expire: Time at which error count will be expired
801802
* @irq_soft_enabled: Are IRQs soft-enabled? If not, IRQ handler will
@@ -940,6 +941,7 @@ struct efx_nic {
940941
int rx_packet_ts_offset;
941942
bool rx_scatter;
942943
struct efx_rss_context rss_context;
944+
struct mutex rss_lock;
943945

944946
unsigned int_error_count;
945947
unsigned long int_error_expire;

drivers/net/ethernet/sfc/nic.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,8 @@ enum {
365365
* @vi_base: Absolute index of first VI in this function
366366
* @n_allocated_vis: Number of VIs allocated to this function
367367
* @must_realloc_vis: Flag: VIs have yet to be reallocated after MC reboot
368+
* @must_restore_rss_contexts: Flag: RSS contexts have yet to be restored after
369+
* MC reboot
368370
* @must_restore_filters: Flag: filters have yet to be restored after MC reboot
369371
* @n_piobufs: Number of PIO buffers allocated to this function
370372
* @wc_membase: Base address of write-combining mapping of the memory BAR
@@ -407,6 +409,7 @@ struct efx_ef10_nic_data {
407409
unsigned int vi_base;
408410
unsigned int n_allocated_vis;
409411
bool must_realloc_vis;
412+
bool must_restore_rss_contexts;
410413
bool must_restore_filters;
411414
unsigned int n_piobufs;
412415
void __iomem *wc_membase, *pio_write_base;

0 commit comments

Comments
 (0)