aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKulikov Vasiliy <segooon@gmail.com>2010-07-08 22:25:22 -0400
committerDavid S. Miller <davem@davemloft.net>2010-07-10 22:42:06 -0400
commitf163530407280485034c836d908b49787a8189bc (patch)
tree0f03dbed022025a5f4d78d5e2b84b8656873c138
parent344dbf1073d1cea179ed0831547cab2b7ea4ea27 (diff)
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>
-rw-r--r--drivers/net/82596.c42
1 files changed, 26 insertions, 16 deletions
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
index dd8dc15556c..73073d0b689 100644
--- a/drivers/net/82596.c
+++ b/drivers/net/82596.c
@@ -525,7 +525,21 @@ static irqreturn_t i596_error(int irq, void *dev_id)
525} 525}
526#endif 526#endif
527 527
528static inline void init_rx_bufs(struct net_device *dev) 528static inline void remove_rx_bufs(struct net_device *dev)
529{
530 struct i596_private *lp = dev->ml_priv;
531 struct i596_rbd *rbd;
532 int i;
533
534 for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
535 if (rbd->skb == NULL)
536 break;
537 dev_kfree_skb(rbd->skb);
538 rbd->skb = NULL;
539 }
540}
541
542static inline int init_rx_bufs(struct net_device *dev)
529{ 543{
530 struct i596_private *lp = dev->ml_priv; 544 struct i596_private *lp = dev->ml_priv;
531 int i; 545 int i;
@@ -537,8 +551,11 @@ static inline void init_rx_bufs(struct net_device *dev)
537 for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) { 551 for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) {
538 struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ); 552 struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ);
539 553
540 if (skb == NULL) 554 if (skb == NULL) {
541 panic("82596: alloc_skb() failed"); 555 remove_rx_bufs(dev);
556 return -ENOMEM;
557 }
558
542 skb->dev = dev; 559 skb->dev = dev;
543 rbd->v_next = rbd+1; 560 rbd->v_next = rbd+1;
544 rbd->b_next = WSWAPrbd(virt_to_bus(rbd+1)); 561 rbd->b_next = WSWAPrbd(virt_to_bus(rbd+1));
@@ -574,19 +591,8 @@ static inline void init_rx_bufs(struct net_device *dev)
574 rfd->v_next = lp->rfds; 591 rfd->v_next = lp->rfds;
575 rfd->b_next = WSWAPrfd(virt_to_bus(lp->rfds)); 592 rfd->b_next = WSWAPrfd(virt_to_bus(lp->rfds));
576 rfd->cmd = CMD_EOL|CMD_FLEX; 593 rfd->cmd = CMD_EOL|CMD_FLEX;
577}
578
579static inline void remove_rx_bufs(struct net_device *dev)
580{
581 struct i596_private *lp = dev->ml_priv;
582 struct i596_rbd *rbd;
583 int i;
584 594
585 for (i = 0, rbd = lp->rbds; i < rx_ring_size; i++, rbd++) { 595 return 0;
586 if (rbd->skb == NULL)
587 break;
588 dev_kfree_skb(rbd->skb);
589 }
590} 596}
591 597
592 598
@@ -1013,7 +1019,11 @@ static int i596_open(struct net_device *dev)
1013 return -EAGAIN; 1019 return -EAGAIN;
1014 } 1020 }
1015#endif 1021#endif
1016 init_rx_bufs(dev); 1022 res = init_rx_bufs(dev);
1023 if (res) {
1024 free_irq(dev->irq, dev);
1025 return res;
1026 }
1017 1027
1018 netif_start_queue(dev); 1028 netif_start_queue(dev);
1019 1029