nfp: wait for posted reconfigs when disabling the device
[ Upstream commit 9ad716b95fd6c6be46a4f2d5936e514b5bcd744d ] To avoid leaking a running timer we need to wait for the posted reconfigs after netdev is unregistered. In common case the process of deinitializing the device will perform synchronous reconfigs which wait for posted requests, but especially with VXLAN ports being actively added and removed there can be a race condition leaving a timer running after adapter structure is freed leading to a crash. Add an explicit flush after deregistering and for a good measure a warning to check if timer is running just before structures are freed. Fixes: 3d780b926a12 ("nfp: add async reconfiguration mechanism") Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com> Reviewed-by: Dirk van der Merwe <dirk.vandermerwe@netronome.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
ade76212f7
commit
eb4f28d8f9
@ -227,6 +227,45 @@ done:
|
||||
spin_unlock_bh(&nn->reconfig_lock);
|
||||
}
|
||||
|
||||
static void nfp_net_reconfig_sync_enter(struct nfp_net *nn)
|
||||
{
|
||||
bool cancelled_timer = false;
|
||||
u32 pre_posted_requests;
|
||||
|
||||
spin_lock_bh(&nn->reconfig_lock);
|
||||
|
||||
nn->reconfig_sync_present = true;
|
||||
|
||||
if (nn->reconfig_timer_active) {
|
||||
nn->reconfig_timer_active = false;
|
||||
cancelled_timer = true;
|
||||
}
|
||||
pre_posted_requests = nn->reconfig_posted;
|
||||
nn->reconfig_posted = 0;
|
||||
|
||||
spin_unlock_bh(&nn->reconfig_lock);
|
||||
|
||||
if (cancelled_timer) {
|
||||
del_timer_sync(&nn->reconfig_timer);
|
||||
nfp_net_reconfig_wait(nn, nn->reconfig_timer.expires);
|
||||
}
|
||||
|
||||
/* Run the posted reconfigs which were issued before we started */
|
||||
if (pre_posted_requests) {
|
||||
nfp_net_reconfig_start(nn, pre_posted_requests);
|
||||
nfp_net_reconfig_wait(nn, jiffies + HZ * NFP_NET_POLL_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
static void nfp_net_reconfig_wait_posted(struct nfp_net *nn)
|
||||
{
|
||||
nfp_net_reconfig_sync_enter(nn);
|
||||
|
||||
spin_lock_bh(&nn->reconfig_lock);
|
||||
nn->reconfig_sync_present = false;
|
||||
spin_unlock_bh(&nn->reconfig_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* nfp_net_reconfig() - Reconfigure the firmware
|
||||
* @nn: NFP Net device to reconfigure
|
||||
@ -240,32 +279,9 @@ done:
|
||||
*/
|
||||
int nfp_net_reconfig(struct nfp_net *nn, u32 update)
|
||||
{
|
||||
bool cancelled_timer = false;
|
||||
u32 pre_posted_requests;
|
||||
int ret;
|
||||
|
||||
spin_lock_bh(&nn->reconfig_lock);
|
||||
|
||||
nn->reconfig_sync_present = true;
|
||||
|
||||
if (nn->reconfig_timer_active) {
|
||||
del_timer(&nn->reconfig_timer);
|
||||
nn->reconfig_timer_active = false;
|
||||
cancelled_timer = true;
|
||||
}
|
||||
pre_posted_requests = nn->reconfig_posted;
|
||||
nn->reconfig_posted = 0;
|
||||
|
||||
spin_unlock_bh(&nn->reconfig_lock);
|
||||
|
||||
if (cancelled_timer)
|
||||
nfp_net_reconfig_wait(nn, nn->reconfig_timer.expires);
|
||||
|
||||
/* Run the posted reconfigs which were issued before we started */
|
||||
if (pre_posted_requests) {
|
||||
nfp_net_reconfig_start(nn, pre_posted_requests);
|
||||
nfp_net_reconfig_wait(nn, jiffies + HZ * NFP_NET_POLL_TIMEOUT);
|
||||
}
|
||||
nfp_net_reconfig_sync_enter(nn);
|
||||
|
||||
nfp_net_reconfig_start(nn, update);
|
||||
ret = nfp_net_reconfig_wait(nn, jiffies + HZ * NFP_NET_POLL_TIMEOUT);
|
||||
@ -3609,6 +3625,7 @@ struct nfp_net *nfp_net_alloc(struct pci_dev *pdev, bool needs_netdev,
|
||||
*/
|
||||
void nfp_net_free(struct nfp_net *nn)
|
||||
{
|
||||
WARN_ON(timer_pending(&nn->reconfig_timer) || nn->reconfig_posted);
|
||||
if (nn->dp.netdev)
|
||||
free_netdev(nn->dp.netdev);
|
||||
else
|
||||
@ -3893,4 +3910,5 @@ void nfp_net_clean(struct nfp_net *nn)
|
||||
return;
|
||||
|
||||
unregister_netdev(nn->dp.netdev);
|
||||
nfp_net_reconfig_wait_posted(nn);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user