Commit f1635304 authored by Kulikov Vasiliy's avatar Kulikov Vasiliy Committed by David S. Miller

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: default avatarKulikov Vasiliy <segooon@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 344dbf10
...@@ -525,7 +525,21 @@ static irqreturn_t i596_error(int irq, void *dev_id) ...@@ -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) ...@@ -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) ...@@ -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)
{
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++) { return 0;
if (rbd->skb == NULL)
break;
dev_kfree_skb(rbd->skb);
}
} }
...@@ -1013,7 +1019,11 @@ static int i596_open(struct net_device *dev) ...@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment