82596: do not panic on out of memory
If dev_alloc_skb() failed then free already allocated skbs. remove_rx_bufs() can be called multiple times, so set rbd->skb to NULL to avoid double free. remove_rx_bufs() was moved upwards to be seen by init_rx_bufs(). Signed-off-by: Kulikov Vasiliy <segooon@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
344dbf1073
commit
f163530407
@@ -525,7 +525,21 @@ static irqreturn_t i596_error(int irq, void *dev_id)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline void init_rx_bufs(struct net_device *dev)
|
static inline void remove_rx_bufs(struct net_device *dev)
|
||||||
|
{
|
||||||
|
struct i596_private *lp = dev->ml_priv;
|
||||||
|
struct i596_rbd *rbd;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
|
||||||
|
if (rbd->skb == NULL)
|
||||||
|
break;
|
||||||
|
dev_kfree_skb(rbd->skb);
|
||||||
|
rbd->skb = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int init_rx_bufs(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct i596_private *lp = dev->ml_priv;
|
struct i596_private *lp = dev->ml_priv;
|
||||||
int i;
|
int i;
|
||||||
@@ -537,8 +551,11 @@ static inline void init_rx_bufs(struct net_device *dev)
|
|||||||
for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
|
for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
|
||||||
struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ);
|
struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ);
|
||||||
|
|
||||||
if (skb == NULL)
|
if (skb == NULL) {
|
||||||
panic("82596: alloc_skb() failed");
|
remove_rx_bufs(dev);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
skb->dev = dev;
|
skb->dev = dev;
|
||||||
rbd->v_next = rbd+1;
|
rbd->v_next = rbd+1;
|
||||||
rbd->b_next = WSWAPrbd(virt_to_bus(rbd+1));
|
rbd->b_next = WSWAPrbd(virt_to_bus(rbd+1));
|
||||||
@@ -574,19 +591,8 @@ static inline void init_rx_bufs(struct net_device *dev)
|
|||||||
rfd->v_next = lp->rfds;
|
rfd->v_next = lp->rfds;
|
||||||
rfd->b_next = WSWAPrfd(virt_to_bus(lp->rfds));
|
rfd->b_next = WSWAPrfd(virt_to_bus(lp->rfds));
|
||||||
rfd->cmd = CMD_EOL|CMD_FLEX;
|
rfd->cmd = CMD_EOL|CMD_FLEX;
|
||||||
}
|
|
||||||
|
|
||||||
static inline void remove_rx_bufs(struct net_device *dev)
|
return 0;
|
||||||
{
|
|
||||||
struct i596_private *lp = dev->ml_priv;
|
|
||||||
struct i596_rbd *rbd;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
|
|
||||||
if (rbd->skb == NULL)
|
|
||||||
break;
|
|
||||||
dev_kfree_skb(rbd->skb);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1013,7 +1019,11 @@ static int i596_open(struct net_device *dev)
|
|||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
init_rx_bufs(dev);
|
res = init_rx_bufs(dev);
|
||||||
|
if (res) {
|
||||||
|
free_irq(dev->irq, dev);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
netif_start_queue(dev);
|
netif_start_queue(dev);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user