Skip to content

Commit 2a5cd6e

Browse files
agotorvalds
authored andcommitted
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 <[email protected]> Cc: Rodolfo Giometti <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 083e586 commit 2a5cd6e

File tree

1 file changed

+11
-8
lines changed

1 file changed

+11
-8
lines changed

drivers/pps/pps.c

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <linux/sched.h>
2828
#include <linux/uaccess.h>
2929
#include <linux/idr.h>
30+
#include <linux/mutex.h>
3031
#include <linux/cdev.h>
3132
#include <linux/poll.h>
3233
#include <linux/pps_kernel.h>
@@ -39,7 +40,7 @@
3940
static dev_t pps_devt;
4041
static struct class *pps_class;
4142

42-
static DEFINE_SPINLOCK(pps_idr_lock);
43+
static DEFINE_MUTEX(pps_idr_lock);
4344
static DEFINE_IDR(pps_idr);
4445

4546
/*
@@ -239,9 +240,9 @@ static void pps_device_destruct(struct device *dev)
239240

240241
/* release id here to protect others from using it while it's
241242
* still in use */
242-
spin_lock_irq(&pps_idr_lock);
243+
mutex_lock(&pps_idr_lock);
243244
idr_remove(&pps_idr, pps->id);
244-
spin_unlock_irq(&pps_idr_lock);
245+
mutex_unlock(&pps_idr_lock);
245246

246247
kfree(dev);
247248
kfree(pps);
@@ -252,17 +253,19 @@ int pps_register_cdev(struct pps_device *pps)
252253
int err;
253254
dev_t devt;
254255

256+
mutex_lock(&pps_idr_lock);
255257
/* 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);
257260
return -ENOMEM;
261+
}
258262

259263
/* Now really allocate the PPS source.
260264
* After idr_get_new() calling the new source will be freely available
261265
* into the kernel.
262266
*/
263-
spin_lock_irq(&pps_idr_lock);
264267
err = idr_get_new(&pps_idr, pps, &pps->id);
265-
spin_unlock_irq(&pps_idr_lock);
268+
mutex_unlock(&pps_idr_lock);
266269

267270
if (err < 0)
268271
return err;
@@ -302,9 +305,9 @@ int pps_register_cdev(struct pps_device *pps)
302305
cdev_del(&pps->cdev);
303306

304307
free_idr:
305-
spin_lock_irq(&pps_idr_lock);
308+
mutex_lock(&pps_idr_lock);
306309
idr_remove(&pps_idr, pps->id);
307-
spin_unlock_irq(&pps_idr_lock);
310+
mutex_unlock(&pps_idr_lock);
308311

309312
return err;
310313
}

0 commit comments

Comments
 (0)