From 2a5cd6e2fb1984cc83f08b3645bf394830ac7825 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Wed, 12 Jan 2011 17:00:53 -0800 Subject: 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 Cc: Rodolfo Giometti Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/pps/pps.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers/pps') diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c index 79b4455..9e15cf1 100644 --- a/drivers/pps/pps.c +++ b/drivers/pps/pps.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -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; } -- cgit v1.1