diff options
author | Alexander Gordeev <lasaine@lvk.cs.msu.su> | 2011-01-13 04:00:53 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-13 19:03:20 +0300 |
commit | 2a5cd6e2fb1984cc83f08b3645bf394830ac7825 (patch) | |
tree | 14082324f971c3d8af26840caf9d68a4524269b7 /drivers/pps | |
parent | 083e58666ff5b3c5750d9a5c0560018b03cfb4b2 (diff) | |
download | linux-2a5cd6e2fb1984cc83f08b3645bf394830ac7825.tar.xz |
pps: make idr lock a mutex and protect idr_pre_get
Now pps_idr_lock is never used in interrupt context so we can replace
spin_lock_irq/spin_unlock_irq with plain spin_lock/spin_unlock. But
there is also a potential race condition when someone can steal an id
which was allocated by idr_pre_get before it is used. So convert spin
lock to mutex and protect the whole id generation process.
Signed-off-by: Alexander Gordeev <lasaine@lvk.cs.msu.su>
Cc: Rodolfo Giometti <giometti@linux.it>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/pps')
-rw-r--r-- | drivers/pps/pps.c | 19 |
1 files changed, 11 insertions, 8 deletions
diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c index 79b445578132..9e15cf1da946 100644 --- a/drivers/pps/pps.c +++ b/drivers/pps/pps.c @@ -27,6 +27,7 @@ #include <linux/sched.h> #include <linux/uaccess.h> #include <linux/idr.h> +#include <linux/mutex.h> #include <linux/cdev.h> #include <linux/poll.h> #include <linux/pps_kernel.h> @@ -39,7 +40,7 @@ static dev_t pps_devt; static struct class *pps_class; -static DEFINE_SPINLOCK(pps_idr_lock); +static DEFINE_MUTEX(pps_idr_lock); static DEFINE_IDR(pps_idr); /* @@ -239,9 +240,9 @@ static void pps_device_destruct(struct device *dev) /* release id here to protect others from using it while it's * still in use */ - spin_lock_irq(&pps_idr_lock); + mutex_lock(&pps_idr_lock); idr_remove(&pps_idr, pps->id); - spin_unlock_irq(&pps_idr_lock); + mutex_unlock(&pps_idr_lock); kfree(dev); kfree(pps); @@ -252,17 +253,19 @@ int pps_register_cdev(struct pps_device *pps) int err; dev_t devt; + mutex_lock(&pps_idr_lock); /* Get new ID for the new PPS source */ - if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0) + if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0) { + mutex_unlock(&pps_idr_lock); return -ENOMEM; + } /* Now really allocate the PPS source. * After idr_get_new() calling the new source will be freely available * into the kernel. */ - spin_lock_irq(&pps_idr_lock); err = idr_get_new(&pps_idr, pps, &pps->id); - spin_unlock_irq(&pps_idr_lock); + mutex_unlock(&pps_idr_lock); if (err < 0) return err; @@ -302,9 +305,9 @@ del_cdev: cdev_del(&pps->cdev); free_idr: - spin_lock_irq(&pps_idr_lock); + mutex_lock(&pps_idr_lock); idr_remove(&pps_idr, pps->id); - spin_unlock_irq(&pps_idr_lock); + mutex_unlock(&pps_idr_lock); return err; } |