Skip to content

Commit f9841bd

Browse files
sreedeviintelanguy11
authored andcommitted
idpf: fix memory leak of flow steer list on rmmod
The flow steering list maintains entries that are added and removed as ethtool creates and deletes flow steering rules. Module removal with active entries causes memory leak as the list is not properly cleaned up. Prevent this by iterating through the remaining entries in the list and freeing the associated memory during module removal. Add a spinlock (flow_steer_list_lock) to protect the list access from multiple threads. Fixes: ada3e24 ("idpf: add flow steering support") Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com> Signed-off-by: Sreedevi Joshi <sreedevi.joshi@intel.com> Reviewed-by: Simon Horman <horms@kernel.org> Tested-by: Mina Almasry <almasrymina@google.com> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
1 parent 4d79221 commit f9841bd

3 files changed

Lines changed: 42 additions & 3 deletions

File tree

drivers/net/ethernet/intel/idpf/idpf.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,13 +558,15 @@ struct idpf_vector_lifo {
558558
* @max_q: Maximum possible queues
559559
* @req_qs_chunks: Queue chunk data for requested queues
560560
* @mac_filter_list_lock: Lock to protect mac filters
561+
* @flow_steer_list_lock: Lock to protect fsteer filters
561562
* @flags: See enum idpf_vport_config_flags
562563
*/
563564
struct idpf_vport_config {
564565
struct idpf_vport_user_config_data user_config;
565566
struct idpf_vport_max_q max_q;
566567
struct virtchnl2_add_queues *req_qs_chunks;
567568
spinlock_t mac_filter_list_lock;
569+
spinlock_t flow_steer_list_lock;
568570
DECLARE_BITMAP(flags, IDPF_VPORT_CONFIG_FLAGS_NBITS);
569571
};
570572

drivers/net/ethernet/intel/idpf/idpf_ethtool.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,16 @@ static int idpf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
3737
{
3838
struct idpf_netdev_priv *np = netdev_priv(netdev);
3939
struct idpf_vport_user_config_data *user_config;
40+
struct idpf_vport_config *vport_config;
4041
struct idpf_fsteer_fltr *f;
4142
struct idpf_vport *vport;
4243
unsigned int cnt = 0;
4344
int err = 0;
4445

4546
idpf_vport_ctrl_lock(netdev);
4647
vport = idpf_netdev_to_vport(netdev);
47-
user_config = &np->adapter->vport_config[np->vport_idx]->user_config;
48+
vport_config = np->adapter->vport_config[np->vport_idx];
49+
user_config = &vport_config->user_config;
4850

4951
switch (cmd->cmd) {
5052
case ETHTOOL_GRXCLSRLCNT:
@@ -53,15 +55,18 @@ static int idpf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
5355
break;
5456
case ETHTOOL_GRXCLSRULE:
5557
err = -EINVAL;
58+
spin_lock_bh(&vport_config->flow_steer_list_lock);
5659
list_for_each_entry(f, &user_config->flow_steer_list, list)
5760
if (f->loc == cmd->fs.location) {
5861
cmd->fs.ring_cookie = f->q_index;
5962
err = 0;
6063
break;
6164
}
65+
spin_unlock_bh(&vport_config->flow_steer_list_lock);
6266
break;
6367
case ETHTOOL_GRXCLSRLALL:
6468
cmd->data = idpf_fsteer_max_rules(vport);
69+
spin_lock_bh(&vport_config->flow_steer_list_lock);
6570
list_for_each_entry(f, &user_config->flow_steer_list, list) {
6671
if (cnt == cmd->rule_cnt) {
6772
err = -EMSGSIZE;
@@ -72,6 +77,7 @@ static int idpf_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
7277
}
7378
if (!err)
7479
cmd->rule_cnt = user_config->num_fsteer_fltrs;
80+
spin_unlock_bh(&vport_config->flow_steer_list_lock);
7581
break;
7682
default:
7783
break;
@@ -240,6 +246,7 @@ static int idpf_add_flow_steer(struct net_device *netdev,
240246

241247
fltr->loc = fsp->location;
242248
fltr->q_index = q_index;
249+
spin_lock_bh(&vport_config->flow_steer_list_lock);
243250
list_for_each_entry(f, &user_config->flow_steer_list, list) {
244251
if (f->loc >= fltr->loc)
245252
break;
@@ -250,6 +257,7 @@ static int idpf_add_flow_steer(struct net_device *netdev,
250257
list_add(&fltr->list, &user_config->flow_steer_list);
251258

252259
user_config->num_fsteer_fltrs++;
260+
spin_unlock_bh(&vport_config->flow_steer_list_lock);
253261

254262
out:
255263
kfree(rule);
@@ -302,17 +310,20 @@ static int idpf_del_flow_steer(struct net_device *netdev,
302310
goto out;
303311
}
304312

313+
spin_lock_bh(&vport_config->flow_steer_list_lock);
305314
list_for_each_entry_safe(f, iter,
306315
&user_config->flow_steer_list, list) {
307316
if (f->loc == fsp->location) {
308317
list_del(&f->list);
309318
kfree(f);
310319
user_config->num_fsteer_fltrs--;
311-
goto out;
320+
goto out_unlock;
312321
}
313322
}
314323
err = -EINVAL;
315324

325+
out_unlock:
326+
spin_unlock_bh(&vport_config->flow_steer_list_lock);
316327
out:
317328
kfree(rule);
318329
return err;

drivers/net/ethernet/intel/idpf/idpf_lib.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,29 @@ int idpf_intr_req(struct idpf_adapter *adapter)
442442
return err;
443443
}
444444

445+
/**
446+
* idpf_del_all_flow_steer_filters - Delete all flow steer filters in list
447+
* @vport: main vport struct
448+
*
449+
* Takes flow_steer_list_lock spinlock. Deletes all filters
450+
*/
451+
static void idpf_del_all_flow_steer_filters(struct idpf_vport *vport)
452+
{
453+
struct idpf_vport_config *vport_config;
454+
struct idpf_fsteer_fltr *f, *ftmp;
455+
456+
vport_config = vport->adapter->vport_config[vport->idx];
457+
458+
spin_lock_bh(&vport_config->flow_steer_list_lock);
459+
list_for_each_entry_safe(f, ftmp, &vport_config->user_config.flow_steer_list,
460+
list) {
461+
list_del(&f->list);
462+
kfree(f);
463+
}
464+
vport_config->user_config.num_fsteer_fltrs = 0;
465+
spin_unlock_bh(&vport_config->flow_steer_list_lock);
466+
}
467+
445468
/**
446469
* idpf_find_mac_filter - Search filter list for specific mac filter
447470
* @vconfig: Vport config structure
@@ -1107,8 +1130,10 @@ static void idpf_vport_dealloc(struct idpf_vport *vport)
11071130
idpf_vport_stop(vport, true);
11081131
idpf_decfg_netdev(vport);
11091132
}
1110-
if (test_bit(IDPF_REMOVE_IN_PROG, adapter->flags))
1133+
if (test_bit(IDPF_REMOVE_IN_PROG, adapter->flags)) {
11111134
idpf_del_all_mac_filters(vport);
1135+
idpf_del_all_flow_steer_filters(vport);
1136+
}
11121137

11131138
if (adapter->netdevs[i]) {
11141139
struct idpf_netdev_priv *np = netdev_priv(adapter->netdevs[i]);
@@ -1648,6 +1673,7 @@ void idpf_init_task(struct work_struct *work)
16481673
vport_config = adapter->vport_config[index];
16491674

16501675
spin_lock_init(&vport_config->mac_filter_list_lock);
1676+
spin_lock_init(&vport_config->flow_steer_list_lock);
16511677

16521678
INIT_LIST_HEAD(&vport_config->user_config.mac_filter_list);
16531679
INIT_LIST_HEAD(&vport_config->user_config.flow_steer_list);

0 commit comments

Comments
 (0)