net: protect NAPI enablement with netdev_lock()
Wrap napi_enable() / napi_disable() with netdev_lock(). Provide the "already locked" flavor of the API. iavf needs the usual adjustment. A number of drivers call napi_enable() under a spin lock, so they have to be modified to take netdev_lock() first, then spin lock then call napi_enable_locked(). Protecting napi_enable() implies that napi->napi_id is protected by netdev_lock(). Acked-by: Francois Romieu <romieu@fr.zoreil.com> # via-velocity Reviewed-by: Eric Dumazet <edumazet@google.com> Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com> Link: https://patch.msgid.link/20250115035319.559603-7-kuba@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
1b23cdbd2b
commit
413f0271f3
6 changed files with 56 additions and 22 deletions
|
@ -462,7 +462,7 @@ static void pcnet32_netif_start(struct net_device *dev)
|
||||||
val = lp->a->read_csr(ioaddr, CSR3);
|
val = lp->a->read_csr(ioaddr, CSR3);
|
||||||
val &= 0x00ff;
|
val &= 0x00ff;
|
||||||
lp->a->write_csr(ioaddr, CSR3, val);
|
lp->a->write_csr(ioaddr, CSR3, val);
|
||||||
napi_enable(&lp->napi);
|
napi_enable_locked(&lp->napi);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -889,6 +889,7 @@ static int pcnet32_set_ringparam(struct net_device *dev,
|
||||||
if (netif_running(dev))
|
if (netif_running(dev))
|
||||||
pcnet32_netif_stop(dev);
|
pcnet32_netif_stop(dev);
|
||||||
|
|
||||||
|
netdev_lock(dev);
|
||||||
spin_lock_irqsave(&lp->lock, flags);
|
spin_lock_irqsave(&lp->lock, flags);
|
||||||
lp->a->write_csr(ioaddr, CSR0, CSR0_STOP); /* stop the chip */
|
lp->a->write_csr(ioaddr, CSR0, CSR0_STOP); /* stop the chip */
|
||||||
|
|
||||||
|
@ -920,6 +921,7 @@ static int pcnet32_set_ringparam(struct net_device *dev,
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&lp->lock, flags);
|
spin_unlock_irqrestore(&lp->lock, flags);
|
||||||
|
netdev_unlock(dev);
|
||||||
|
|
||||||
netif_info(lp, drv, dev, "Ring Param Settings: RX: %d, TX: %d\n",
|
netif_info(lp, drv, dev, "Ring Param Settings: RX: %d, TX: %d\n",
|
||||||
lp->rx_ring_size, lp->tx_ring_size);
|
lp->rx_ring_size, lp->tx_ring_size);
|
||||||
|
@ -985,6 +987,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1)
|
||||||
if (netif_running(dev))
|
if (netif_running(dev))
|
||||||
pcnet32_netif_stop(dev);
|
pcnet32_netif_stop(dev);
|
||||||
|
|
||||||
|
netdev_lock(dev);
|
||||||
spin_lock_irqsave(&lp->lock, flags);
|
spin_lock_irqsave(&lp->lock, flags);
|
||||||
lp->a->write_csr(ioaddr, CSR0, CSR0_STOP); /* stop the chip */
|
lp->a->write_csr(ioaddr, CSR0, CSR0_STOP); /* stop the chip */
|
||||||
|
|
||||||
|
@ -1122,6 +1125,7 @@ clean_up:
|
||||||
lp->a->write_bcr(ioaddr, 20, 4); /* return to 16bit mode */
|
lp->a->write_bcr(ioaddr, 20, 4); /* return to 16bit mode */
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&lp->lock, flags);
|
spin_unlock_irqrestore(&lp->lock, flags);
|
||||||
|
netdev_unlock(dev);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
} /* end pcnet32_loopback_test */
|
} /* end pcnet32_loopback_test */
|
||||||
|
@ -2101,6 +2105,7 @@ static int pcnet32_open(struct net_device *dev)
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
netdev_lock(dev);
|
||||||
spin_lock_irqsave(&lp->lock, flags);
|
spin_lock_irqsave(&lp->lock, flags);
|
||||||
/* Check for a valid station address */
|
/* Check for a valid station address */
|
||||||
if (!is_valid_ether_addr(dev->dev_addr)) {
|
if (!is_valid_ether_addr(dev->dev_addr)) {
|
||||||
|
@ -2266,7 +2271,7 @@ static int pcnet32_open(struct net_device *dev)
|
||||||
goto err_free_ring;
|
goto err_free_ring;
|
||||||
}
|
}
|
||||||
|
|
||||||
napi_enable(&lp->napi);
|
napi_enable_locked(&lp->napi);
|
||||||
|
|
||||||
/* Re-initialize the PCNET32, and start it when done. */
|
/* Re-initialize the PCNET32, and start it when done. */
|
||||||
lp->a->write_csr(ioaddr, 1, (lp->init_dma_addr & 0xffff));
|
lp->a->write_csr(ioaddr, 1, (lp->init_dma_addr & 0xffff));
|
||||||
|
@ -2300,6 +2305,7 @@ static int pcnet32_open(struct net_device *dev)
|
||||||
lp->a->read_csr(ioaddr, CSR0));
|
lp->a->read_csr(ioaddr, CSR0));
|
||||||
|
|
||||||
spin_unlock_irqrestore(&lp->lock, flags);
|
spin_unlock_irqrestore(&lp->lock, flags);
|
||||||
|
netdev_unlock(dev);
|
||||||
|
|
||||||
return 0; /* Always succeed */
|
return 0; /* Always succeed */
|
||||||
|
|
||||||
|
@ -2315,6 +2321,7 @@ err_free_ring:
|
||||||
|
|
||||||
err_free_irq:
|
err_free_irq:
|
||||||
spin_unlock_irqrestore(&lp->lock, flags);
|
spin_unlock_irqrestore(&lp->lock, flags);
|
||||||
|
netdev_unlock(dev);
|
||||||
free_irq(dev->irq, dev);
|
free_irq(dev->irq, dev);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1180,7 +1180,7 @@ static void iavf_napi_enable_all(struct iavf_adapter *adapter)
|
||||||
|
|
||||||
q_vector = &adapter->q_vectors[q_idx];
|
q_vector = &adapter->q_vectors[q_idx];
|
||||||
napi = &q_vector->napi;
|
napi = &q_vector->napi;
|
||||||
napi_enable(napi);
|
napi_enable_locked(napi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1196,7 +1196,7 @@ static void iavf_napi_disable_all(struct iavf_adapter *adapter)
|
||||||
|
|
||||||
for (q_idx = 0; q_idx < q_vectors; q_idx++) {
|
for (q_idx = 0; q_idx < q_vectors; q_idx++) {
|
||||||
q_vector = &adapter->q_vectors[q_idx];
|
q_vector = &adapter->q_vectors[q_idx];
|
||||||
napi_disable(&q_vector->napi);
|
napi_disable_locked(&q_vector->napi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4392,6 +4392,7 @@ static int mvneta_cpu_online(unsigned int cpu, struct hlist_node *node)
|
||||||
if (pp->neta_armada3700)
|
if (pp->neta_armada3700)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
netdev_lock(port->napi.dev);
|
||||||
spin_lock(&pp->lock);
|
spin_lock(&pp->lock);
|
||||||
/*
|
/*
|
||||||
* Configuring the driver for a new CPU while the driver is
|
* Configuring the driver for a new CPU while the driver is
|
||||||
|
@ -4418,7 +4419,7 @@ static int mvneta_cpu_online(unsigned int cpu, struct hlist_node *node)
|
||||||
|
|
||||||
/* Mask all ethernet port interrupts */
|
/* Mask all ethernet port interrupts */
|
||||||
on_each_cpu(mvneta_percpu_mask_interrupt, pp, true);
|
on_each_cpu(mvneta_percpu_mask_interrupt, pp, true);
|
||||||
napi_enable(&port->napi);
|
napi_enable_locked(&port->napi);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enable per-CPU interrupts on the CPU that is
|
* Enable per-CPU interrupts on the CPU that is
|
||||||
|
@ -4439,6 +4440,8 @@ static int mvneta_cpu_online(unsigned int cpu, struct hlist_node *node)
|
||||||
MVNETA_CAUSE_LINK_CHANGE);
|
MVNETA_CAUSE_LINK_CHANGE);
|
||||||
netif_tx_start_all_queues(pp->dev);
|
netif_tx_start_all_queues(pp->dev);
|
||||||
spin_unlock(&pp->lock);
|
spin_unlock(&pp->lock);
|
||||||
|
netdev_unlock(port->napi.dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2320,7 +2320,8 @@ static int velocity_change_mtu(struct net_device *dev, int new_mtu)
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto out_free_tmp_vptr_1;
|
goto out_free_tmp_vptr_1;
|
||||||
|
|
||||||
napi_disable(&vptr->napi);
|
netdev_lock(dev);
|
||||||
|
napi_disable_locked(&vptr->napi);
|
||||||
|
|
||||||
spin_lock_irqsave(&vptr->lock, flags);
|
spin_lock_irqsave(&vptr->lock, flags);
|
||||||
|
|
||||||
|
@ -2342,12 +2343,13 @@ static int velocity_change_mtu(struct net_device *dev, int new_mtu)
|
||||||
|
|
||||||
velocity_give_many_rx_descs(vptr);
|
velocity_give_many_rx_descs(vptr);
|
||||||
|
|
||||||
napi_enable(&vptr->napi);
|
napi_enable_locked(&vptr->napi);
|
||||||
|
|
||||||
mac_enable_int(vptr->mac_regs);
|
mac_enable_int(vptr->mac_regs);
|
||||||
netif_start_queue(dev);
|
netif_start_queue(dev);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&vptr->lock, flags);
|
spin_unlock_irqrestore(&vptr->lock, flags);
|
||||||
|
netdev_unlock(dev);
|
||||||
|
|
||||||
velocity_free_rings(tmp_vptr);
|
velocity_free_rings(tmp_vptr);
|
||||||
|
|
||||||
|
|
|
@ -382,7 +382,7 @@ struct napi_struct {
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
struct list_head rx_list; /* Pending GRO_NORMAL skbs */
|
struct list_head rx_list; /* Pending GRO_NORMAL skbs */
|
||||||
int rx_count; /* length of rx_list */
|
int rx_count; /* length of rx_list */
|
||||||
unsigned int napi_id;
|
unsigned int napi_id; /* protected by netdev_lock */
|
||||||
struct hrtimer timer;
|
struct hrtimer timer;
|
||||||
struct task_struct *thread;
|
struct task_struct *thread;
|
||||||
unsigned long gro_flush_timeout;
|
unsigned long gro_flush_timeout;
|
||||||
|
@ -570,16 +570,11 @@ static inline bool napi_complete(struct napi_struct *n)
|
||||||
|
|
||||||
int dev_set_threaded(struct net_device *dev, bool threaded);
|
int dev_set_threaded(struct net_device *dev, bool threaded);
|
||||||
|
|
||||||
/**
|
|
||||||
* napi_disable - prevent NAPI from scheduling
|
|
||||||
* @n: NAPI context
|
|
||||||
*
|
|
||||||
* Stop NAPI from being scheduled on this context.
|
|
||||||
* Waits till any outstanding processing completes.
|
|
||||||
*/
|
|
||||||
void napi_disable(struct napi_struct *n);
|
void napi_disable(struct napi_struct *n);
|
||||||
|
void napi_disable_locked(struct napi_struct *n);
|
||||||
|
|
||||||
void napi_enable(struct napi_struct *n);
|
void napi_enable(struct napi_struct *n);
|
||||||
|
void napi_enable_locked(struct napi_struct *n);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* napi_synchronize - wait until NAPI is not running
|
* napi_synchronize - wait until NAPI is not running
|
||||||
|
|
|
@ -6958,11 +6958,13 @@ void netif_napi_add_weight_locked(struct net_device *dev,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(netif_napi_add_weight_locked);
|
EXPORT_SYMBOL(netif_napi_add_weight_locked);
|
||||||
|
|
||||||
void napi_disable(struct napi_struct *n)
|
void napi_disable_locked(struct napi_struct *n)
|
||||||
{
|
{
|
||||||
unsigned long val, new;
|
unsigned long val, new;
|
||||||
|
|
||||||
might_sleep();
|
might_sleep();
|
||||||
|
netdev_assert_locked(n->dev);
|
||||||
|
|
||||||
set_bit(NAPI_STATE_DISABLE, &n->state);
|
set_bit(NAPI_STATE_DISABLE, &n->state);
|
||||||
|
|
||||||
val = READ_ONCE(n->state);
|
val = READ_ONCE(n->state);
|
||||||
|
@ -6985,16 +6987,25 @@ void napi_disable(struct napi_struct *n)
|
||||||
|
|
||||||
clear_bit(NAPI_STATE_DISABLE, &n->state);
|
clear_bit(NAPI_STATE_DISABLE, &n->state);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(napi_disable);
|
EXPORT_SYMBOL(napi_disable_locked);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* napi_enable - enable NAPI scheduling
|
* napi_disable() - prevent NAPI from scheduling
|
||||||
* @n: NAPI context
|
* @n: NAPI context
|
||||||
*
|
*
|
||||||
* Resume NAPI from being scheduled on this context.
|
* Stop NAPI from being scheduled on this context.
|
||||||
* Must be paired with napi_disable.
|
* Waits till any outstanding processing completes.
|
||||||
|
* Takes netdev_lock() for associated net_device.
|
||||||
*/
|
*/
|
||||||
void napi_enable(struct napi_struct *n)
|
void napi_disable(struct napi_struct *n)
|
||||||
|
{
|
||||||
|
netdev_lock(n->dev);
|
||||||
|
napi_disable_locked(n);
|
||||||
|
netdev_unlock(n->dev);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(napi_disable);
|
||||||
|
|
||||||
|
void napi_enable_locked(struct napi_struct *n)
|
||||||
{
|
{
|
||||||
unsigned long new, val = READ_ONCE(n->state);
|
unsigned long new, val = READ_ONCE(n->state);
|
||||||
|
|
||||||
|
@ -7011,6 +7022,22 @@ void napi_enable(struct napi_struct *n)
|
||||||
new |= NAPIF_STATE_THREADED;
|
new |= NAPIF_STATE_THREADED;
|
||||||
} while (!try_cmpxchg(&n->state, &val, new));
|
} while (!try_cmpxchg(&n->state, &val, new));
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(napi_enable_locked);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* napi_enable() - enable NAPI scheduling
|
||||||
|
* @n: NAPI context
|
||||||
|
*
|
||||||
|
* Enable scheduling of a NAPI instance.
|
||||||
|
* Must be paired with napi_disable().
|
||||||
|
* Takes netdev_lock() for associated net_device.
|
||||||
|
*/
|
||||||
|
void napi_enable(struct napi_struct *n)
|
||||||
|
{
|
||||||
|
netdev_lock(n->dev);
|
||||||
|
napi_enable_locked(n);
|
||||||
|
netdev_unlock(n->dev);
|
||||||
|
}
|
||||||
EXPORT_SYMBOL(napi_enable);
|
EXPORT_SYMBOL(napi_enable);
|
||||||
|
|
||||||
static void flush_gro_hash(struct napi_struct *napi)
|
static void flush_gro_hash(struct napi_struct *napi)
|
||||||
|
|
Loading…
Add table
Reference in a new issue