From b597ef4712c05c962640a655386a7f06cc1a1fbc Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 2 Jun 2005 16:36:00 -0700 Subject: [PATCH] [NET]: Fix locking in shaper driver. o use a semaphore instead of an opencoded and racy lock o move locking out of shaper_kick and into the callers - most just released the lock before calling shaper_kick o remove in_interrupt() tests. from ->close we can always block, from ->hard_start_xmit and timer context never Signed-off-by: Christoph Hellwig Signed-off-by: David S. Miller --- drivers/net/shaper.c | 86 +++++++++------------------------------ include/linux/if_shaper.h | 3 +- 2 files changed, 20 insertions(+), 69 deletions(-) diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c index e68cf5fb4920..20edeb345792 100644 --- a/drivers/net/shaper.c +++ b/drivers/net/shaper.c @@ -100,35 +100,8 @@ static int sh_debug; /* Debug flag */ #define SHAPER_BANNER "CymruNet Traffic Shaper BETA 0.04 for Linux 2.1\n" -/* - * Locking - */ - -static int shaper_lock(struct shaper *sh) -{ - /* - * Lock in an interrupt must fail - */ - while (test_and_set_bit(0, &sh->locked)) - { - if (!in_interrupt()) - sleep_on(&sh->wait_queue); - else - return 0; - - } - return 1; -} - static void shaper_kick(struct shaper *sh); -static void shaper_unlock(struct shaper *sh) -{ - clear_bit(0, &sh->locked); - wake_up(&sh->wait_queue); - shaper_kick(sh); -} - /* * Compute clocks on a buffer */ @@ -157,17 +130,15 @@ static void shaper_setspeed(struct shaper *shaper, int bitspersec) * Throw a frame at a shaper. */ -static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb) + +static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev) { + struct shaper *shaper = dev->priv; struct sk_buff *ptr; - /* - * Get ready to work on this shaper. Lock may fail if its - * an interrupt and locked. - */ - - if(!shaper_lock(shaper)) - return -1; + if (down_trylock(&shaper->sem)) + return -1; + ptr=shaper->sendq.prev; /* @@ -260,7 +231,8 @@ static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb) dev_kfree_skb(ptr); shaper->stats.collisions++; } - shaper_unlock(shaper); + shaper_kick(shaper); + up(&shaper->sem); return 0; } @@ -297,8 +269,13 @@ static void shaper_queue_xmit(struct shaper *shaper, struct sk_buff *skb) static void shaper_timer(unsigned long data) { - struct shaper *sh=(struct shaper *)data; - shaper_kick(sh); + struct shaper *shaper = (struct shaper *)data; + + if (!down_trylock(&shaper->sem)) { + shaper_kick(shaper); + up(&shaper->sem); + } else + mod_timer(&shaper->timer, jiffies); } /* @@ -310,19 +287,6 @@ static void shaper_kick(struct shaper *shaper) { struct sk_buff *skb; - /* - * Shaper unlock will kick - */ - - if (test_and_set_bit(0, &shaper->locked)) - { - if(sh_debug) - printk("Shaper locked.\n"); - mod_timer(&shaper->timer, jiffies); - return; - } - - /* * Walk the list (may be empty) */ @@ -364,8 +328,6 @@ static void shaper_kick(struct shaper *shaper) if(skb!=NULL) mod_timer(&shaper->timer, SHAPERCB(skb)->shapeclock); - - clear_bit(0, &shaper->locked); } @@ -376,14 +338,12 @@ static void shaper_kick(struct shaper *shaper) static void shaper_flush(struct shaper *shaper) { struct sk_buff *skb; - if(!shaper_lock(shaper)) - { - printk(KERN_ERR "shaper: shaper_flush() called by an irq!\n"); - return; - } + + down(&shaper->sem); while((skb=skb_dequeue(&shaper->sendq))!=NULL) dev_kfree_skb(skb); - shaper_unlock(shaper); + shaper_kick(shaper); + up(&shaper->sem); } /* @@ -426,13 +386,6 @@ static int shaper_close(struct net_device *dev) * ARP and other resolutions and not before. */ - -static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct shaper *sh=dev->priv; - return shaper_qframe(sh, skb); -} - static struct net_device_stats *shaper_get_stats(struct net_device *dev) { struct shaper *sh=dev->priv; @@ -623,7 +576,6 @@ static void shaper_init_priv(struct net_device *dev) init_timer(&sh->timer); sh->timer.function=shaper_timer; sh->timer.data=(unsigned long)sh; - init_waitqueue_head(&sh->wait_queue); } /* diff --git a/include/linux/if_shaper.h b/include/linux/if_shaper.h index 0485b256d043..004e6f09a6e2 100644 --- a/include/linux/if_shaper.h +++ b/include/linux/if_shaper.h @@ -23,7 +23,7 @@ struct shaper __u32 shapeclock; unsigned long recovery; /* Time we can next clock a packet out on an empty queue */ - unsigned long locked; + struct semaphore sem; struct net_device_stats stats; struct net_device *dev; int (*hard_start_xmit) (struct sk_buff *skb, @@ -38,7 +38,6 @@ struct shaper int (*hard_header_cache)(struct neighbour *neigh, struct hh_cache *hh); void (*header_cache_update)(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr); struct net_device_stats* (*get_stats)(struct net_device *dev); - wait_queue_head_t wait_queue; struct timer_list timer; }; -- 2.20.1