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 | } |