Skip to content

Commit 083e586

Browse files
agotorvalds
authored andcommitted
pps: move idr stuff to pps.c
Since now idr is only used to manage char device id's and not used in kernel API anymore it should be moved to pps.c. This also makes it possible to release id only at actual device freeing so nobody can register a pps device with the same id while our device is not freed yet. Signed-off-by: Alexander Gordeev <[email protected]> Acked-by: Rodolfo Giometti <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 7f7cce7 commit 083e586

File tree

2 files changed

+52
-54
lines changed

2 files changed

+52
-54
lines changed

drivers/pps/kapi.c

Lines changed: 3 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,10 @@
2727
#include <linux/sched.h>
2828
#include <linux/time.h>
2929
#include <linux/spinlock.h>
30-
#include <linux/idr.h>
3130
#include <linux/fs.h>
3231
#include <linux/pps_kernel.h>
3332
#include <linux/slab.h>
3433

35-
/*
36-
* Local variables
37-
*/
38-
39-
static DEFINE_SPINLOCK(pps_idr_lock);
40-
static DEFINE_IDR(pps_idr);
41-
4234
/*
4335
* Local functions
4436
*/
@@ -76,7 +68,6 @@ struct pps_device *pps_register_source(struct pps_source_info *info,
7668
int default_params)
7769
{
7870
struct pps_device *pps;
79-
int id;
8071
int err;
8172

8273
/* Sanity checks */
@@ -117,54 +108,18 @@ struct pps_device *pps_register_source(struct pps_source_info *info,
117108
init_waitqueue_head(&pps->queue);
118109
spin_lock_init(&pps->lock);
119110

120-
/* Get new ID for the new PPS source */
121-
if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0) {
122-
err = -ENOMEM;
123-
goto kfree_pps;
124-
}
125-
126-
spin_lock_irq(&pps_idr_lock);
127-
128-
/* Now really allocate the PPS source.
129-
* After idr_get_new() calling the new source will be freely available
130-
* into the kernel.
131-
*/
132-
err = idr_get_new(&pps_idr, pps, &id);
133-
if (err < 0) {
134-
spin_unlock_irq(&pps_idr_lock);
135-
goto kfree_pps;
136-
}
137-
138-
id = id & MAX_ID_MASK;
139-
if (id >= PPS_MAX_SOURCES) {
140-
spin_unlock_irq(&pps_idr_lock);
141-
142-
pr_err("%s: too many PPS sources in the system\n",
143-
info->name);
144-
err = -EBUSY;
145-
goto free_idr;
146-
}
147-
pps->id = id;
148-
149-
spin_unlock_irq(&pps_idr_lock);
150-
151111
/* Create the char device */
152112
err = pps_register_cdev(pps);
153113
if (err < 0) {
154114
pr_err("%s: unable to create char device\n",
155115
info->name);
156-
goto free_idr;
116+
goto kfree_pps;
157117
}
158118

159119
dev_info(pps->dev, "new PPS source %s\n", info->name);
160120

161121
return pps;
162122

163-
free_idr:
164-
spin_lock_irq(&pps_idr_lock);
165-
idr_remove(&pps_idr, id);
166-
spin_unlock_irq(&pps_idr_lock);
167-
168123
kfree_pps:
169124
kfree(pps);
170125

@@ -184,15 +139,10 @@ EXPORT_SYMBOL(pps_register_source);
184139

185140
void pps_unregister_source(struct pps_device *pps)
186141
{
187-
unsigned int id = pps->id;
188-
189142
pps_unregister_cdev(pps);
190143

191-
spin_lock_irq(&pps_idr_lock);
192-
idr_remove(&pps_idr, pps->id);
193-
spin_unlock_irq(&pps_idr_lock);
194-
195-
kfree(pps);
144+
/* don't have to kfree(pps) here because it will be done on
145+
* device destruction */
196146
}
197147
EXPORT_SYMBOL(pps_unregister_source);
198148

drivers/pps/pps.c

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <linux/cdev.h>
3131
#include <linux/poll.h>
3232
#include <linux/pps_kernel.h>
33+
#include <linux/slab.h>
3334

3435
/*
3536
* Local variables
@@ -38,6 +39,9 @@
3839
static dev_t pps_devt;
3940
static struct class *pps_class;
4041

42+
static DEFINE_SPINLOCK(pps_idr_lock);
43+
static DEFINE_IDR(pps_idr);
44+
4145
/*
4246
* Char device methods
4347
*/
@@ -229,11 +233,48 @@ static const struct file_operations pps_cdev_fops = {
229233
.release = pps_cdev_release,
230234
};
231235

236+
static void pps_device_destruct(struct device *dev)
237+
{
238+
struct pps_device *pps = dev_get_drvdata(dev);
239+
240+
/* release id here to protect others from using it while it's
241+
* still in use */
242+
spin_lock_irq(&pps_idr_lock);
243+
idr_remove(&pps_idr, pps->id);
244+
spin_unlock_irq(&pps_idr_lock);
245+
246+
kfree(dev);
247+
kfree(pps);
248+
}
249+
232250
int pps_register_cdev(struct pps_device *pps)
233251
{
234252
int err;
235253
dev_t devt;
236254

255+
/* Get new ID for the new PPS source */
256+
if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0)
257+
return -ENOMEM;
258+
259+
/* Now really allocate the PPS source.
260+
* After idr_get_new() calling the new source will be freely available
261+
* into the kernel.
262+
*/
263+
spin_lock_irq(&pps_idr_lock);
264+
err = idr_get_new(&pps_idr, pps, &pps->id);
265+
spin_unlock_irq(&pps_idr_lock);
266+
267+
if (err < 0)
268+
return err;
269+
270+
pps->id &= MAX_ID_MASK;
271+
if (pps->id >= PPS_MAX_SOURCES) {
272+
pr_err("%s: too many PPS sources in the system\n",
273+
pps->info.name);
274+
err = -EBUSY;
275+
goto free_idr;
276+
}
277+
237278
devt = MKDEV(MAJOR(pps_devt), pps->id);
238279

239280
cdev_init(&pps->cdev, &pps_cdev_fops);
@@ -243,13 +284,15 @@ int pps_register_cdev(struct pps_device *pps)
243284
if (err) {
244285
pr_err("%s: failed to add char device %d:%d\n",
245286
pps->info.name, MAJOR(pps_devt), pps->id);
246-
return err;
287+
goto free_idr;
247288
}
248289
pps->dev = device_create(pps_class, pps->info.dev, devt, pps,
249290
"pps%d", pps->id);
250291
if (IS_ERR(pps->dev))
251292
goto del_cdev;
252293

294+
pps->dev->release = pps_device_destruct;
295+
253296
pr_debug("source %s got cdev (%d:%d)\n", pps->info.name,
254297
MAJOR(pps_devt), pps->id);
255298

@@ -258,6 +301,11 @@ int pps_register_cdev(struct pps_device *pps)
258301
del_cdev:
259302
cdev_del(&pps->cdev);
260303

304+
free_idr:
305+
spin_lock_irq(&pps_idr_lock);
306+
idr_remove(&pps_idr, pps->id);
307+
spin_unlock_irq(&pps_idr_lock);
308+
261309
return err;
262310
}
263311

0 commit comments

Comments
 (0)