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

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
Loading
Loading
Loading
Loading
+26 −16
Original line number Diff line number Diff line
@@ -525,7 +525,21 @@ static irqreturn_t i596_error(int irq, void *dev_id)
}
#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;
	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++) {
		struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ);

		if (skb == NULL)
			panic("82596: alloc_skb() failed");
		if (skb == NULL) {
			remove_rx_bufs(dev);
			return -ENOMEM;
		}

		skb->dev = dev;
		rbd->v_next = 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->b_next = WSWAPrfd(virt_to_bus(lp->rfds));
	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++) {
		if (rbd->skb == NULL)
			break;
		dev_kfree_skb(rbd->skb);
	}
	return 0;
}


@@ -1013,7 +1019,11 @@ static int i596_open(struct net_device *dev)
			return -EAGAIN;
	}
#endif
	init_rx_bufs(dev);
	res = init_rx_bufs(dev);
	if (res) {
		free_irq(dev->irq, dev);
		return res;
	}

	netif_start_queue(dev);