diff options
Diffstat (limited to 'arch/um/drivers/net_kern.c')
| -rw-r--r-- | arch/um/drivers/net_kern.c | 47 | 
1 files changed, 47 insertions, 0 deletions
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index 59811cc880e..8c01fa81a1a 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -34,6 +34,46 @@ static inline void set_ether_mac(struct net_device *dev, unsigned char *addr)  static DEFINE_SPINLOCK(opened_lock);  static LIST_HEAD(opened); +/* + * The drop_skb is used when we can't allocate an skb.  The + * packet is read into drop_skb in order to get the data off the + * connection to the host. + * It is reallocated whenever a maximum packet size is seen which is + * larger than any seen before.  update_drop_skb is called from + * eth_configure when a new interface is added. + */ +static DEFINE_SPINLOCK(drop_lock); +static struct sk_buff *drop_skb; +static int drop_max; + +static int update_drop_skb(int max) +{ +	struct sk_buff *new; +	unsigned long flags; +	int err = 0; + +	spin_lock_irqsave(&drop_lock, flags); + +	if (max <= drop_max) +		goto out; + +	err = -ENOMEM; +	new = dev_alloc_skb(max); +	if (new == NULL) +		goto out; + +	skb_put(new, max); + +	kfree_skb(drop_skb); +	drop_skb = new; +	drop_max = max; +	err = 0; +out: +	spin_unlock_irqrestore(&drop_lock, flags); + +	return err; +} +  static int uml_net_rx(struct net_device *dev)  {  	struct uml_net_private *lp = dev->priv; @@ -43,6 +83,9 @@ static int uml_net_rx(struct net_device *dev)  	/* If we can't allocate memory, try again next round. */  	skb = dev_alloc_skb(lp->max_packet);  	if (skb == NULL) { +		drop_skb->dev = dev; +		/* Read a packet into drop_skb and don't do anything with it. */ +		(*lp->read)(lp->fd, drop_skb, lp);  		lp->stats.rx_dropped++;  		return 0;  	} @@ -447,6 +490,10 @@ static void eth_configure(int n, void *init, char *mac,  	dev->watchdog_timeo = (HZ >> 1);  	dev->irq = UM_ETH_IRQ; +	err = update_drop_skb(lp->max_packet); +	if (err) +		goto out_undo_user_init; +  	rtnl_lock();  	err = register_netdevice(dev);  	rtnl_unlock();  |