diff options
| author | Alexander Gordeev <lasaine@lvk.cs.msu.su> | 2011-01-12 20:00:53 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-13 11:03:20 -0500 |
| commit | 2a5cd6e2fb1984cc83f08b3645bf394830ac7825 (patch) | |
| tree | 14082324f971c3d8af26840caf9d68a4524269b7 /drivers/pps | |
| parent | 083e58666ff5b3c5750d9a5c0560018b03cfb4b2 (diff) | |
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 @@ | |||
| 27 | #include <linux/sched.h> | 27 | #include <linux/sched.h> |
| 28 | #include <linux/uaccess.h> | 28 | #include <linux/uaccess.h> |
| 29 | #include <linux/idr.h> | 29 | #include <linux/idr.h> |
| 30 | #include <linux/mutex.h> | ||
| 30 | #include <linux/cdev.h> | 31 | #include <linux/cdev.h> |
| 31 | #include <linux/poll.h> | 32 | #include <linux/poll.h> |
| 32 | #include <linux/pps_kernel.h> | 33 | #include <linux/pps_kernel.h> |
| @@ -39,7 +40,7 @@ | |||
| 39 | static dev_t pps_devt; | 40 | static dev_t pps_devt; |
| 40 | static struct class *pps_class; | 41 | static struct class *pps_class; |
| 41 | 42 | ||
| 42 | static DEFINE_SPINLOCK(pps_idr_lock); | 43 | static DEFINE_MUTEX(pps_idr_lock); |
| 43 | static DEFINE_IDR(pps_idr); | 44 | static DEFINE_IDR(pps_idr); |
| 44 | 45 | ||
| 45 | /* | 46 | /* |
| @@ -239,9 +240,9 @@ static void pps_device_destruct(struct device *dev) | |||
| 239 | 240 | ||
| 240 | /* release id here to protect others from using it while it's | 241 | /* release id here to protect others from using it while it's |
| 241 | * still in use */ | 242 | * still in use */ |
| 242 | spin_lock_irq(&pps_idr_lock); | 243 | mutex_lock(&pps_idr_lock); |
| 243 | idr_remove(&pps_idr, pps->id); | 244 | idr_remove(&pps_idr, pps->id); |
| 244 | spin_unlock_irq(&pps_idr_lock); | 245 | mutex_unlock(&pps_idr_lock); |
| 245 | 246 | ||
| 246 | kfree(dev); | 247 | kfree(dev); |
| 247 | kfree(pps); | 248 | kfree(pps); |
| @@ -252,17 +253,19 @@ int pps_register_cdev(struct pps_device *pps) | |||
| 252 | int err; | 253 | int err; |
| 253 | dev_t devt; | 254 | dev_t devt; |
| 254 | 255 | ||
| 256 | mutex_lock(&pps_idr_lock); | ||
| 255 | /* Get new ID for the new PPS source */ | 257 | /* Get new ID for the new PPS source */ |
| 256 | if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0) | 258 | if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0) { |
| 259 | mutex_unlock(&pps_idr_lock); | ||
| 257 | return -ENOMEM; | 260 | return -ENOMEM; |
| 261 | } | ||
| 258 | 262 | ||
| 259 | /* Now really allocate the PPS source. | 263 | /* Now really allocate the PPS source. |
| 260 | * After idr_get_new() calling the new source will be freely available | 264 | * After idr_get_new() calling the new source will be freely available |
| 261 | * into the kernel. | 265 | * into the kernel. |
| 262 | */ | 266 | */ |
| 263 | spin_lock_irq(&pps_idr_lock); | ||
| 264 | err = idr_get_new(&pps_idr, pps, &pps->id); | 267 | err = idr_get_new(&pps_idr, pps, &pps->id); |
| 265 | spin_unlock_irq(&pps_idr_lock); | 268 | mutex_unlock(&pps_idr_lock); |
| 266 | 269 | ||
| 267 | if (err < 0) | 270 | if (err < 0) |
| 268 | return err; | 271 | return err; |
| @@ -302,9 +305,9 @@ del_cdev: | |||
| 302 | cdev_del(&pps->cdev); | 305 | cdev_del(&pps->cdev); |
| 303 | 306 | ||
| 304 | free_idr: | 307 | free_idr: |
| 305 | spin_lock_irq(&pps_idr_lock); | 308 | mutex_lock(&pps_idr_lock); |
| 306 | idr_remove(&pps_idr, pps->id); | 309 | idr_remove(&pps_idr, pps->id); |
| 307 | spin_unlock_irq(&pps_idr_lock); | 310 | mutex_unlock(&pps_idr_lock); |
| 308 | 311 | ||
| 309 | return err; | 312 | return err; |
| 310 | } | 313 | } |
