RFC: Boiler plate functions for ida / idr allocation?
Subsystems (8)
One bit of common functionality that a lot of subsystem cores (and some drivers) implement is allocation of unique id's.
Now we have ida / idr for this. However, given I copied someone else's code for those in IIO, I took a look around to see how common these 20 ish lines of code were.
The answer is fairly, though in some cases in subtly different forms. Seems to be from a naive standpoint to be a classic case for a convenient library function.
Taking ida's first, how about the following patch? I'm not at all attached to the form it takes, merely to cutting out on the cut and paste.
Note I've done only a few random places. There aren't that many ida users and I've only played with that for now.
Remaining ida cases:
drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c: (cleans up in case of out of range) drivers/scsi/osd/osd_uld.c: (locks not taken)
However, a few users of idr's that look like they are using them only as idas (perhaps predating ida availability?)
e.g.drivers/hwmon/hwmon.c
The other thing this highlights is that I suspect quite a few are protected by spin locks when a mutex would be fine. Hence that might be worth tidying up first.
Anyhow, a cleanup worth making? (obviously the exact form needs some work, but I think the following is enough to start a discussion!)
Subject: [PATCH] ida utility function
--- drivers/misc/cb710/core.c | 15 +----- drivers/scsi/sd.c | 10 +---- drivers/staging/iio/iio.h | 1 - drivers/staging/iio/industrialio-core.c | 38 ++-------------- drivers/staging/iio/industrialio-trigger.c | 65 ++++++---------------------- include/linux/idr.h | 1 + lib/idr.c | 20 +++++++++ 7 files changed, 42 insertions(+), 108 deletions(-)
drivers/misc/cb710/core.c +3 -12
@@ -254,18 +254,9 @@ static int __devinit cb710_probe(struct pci_dev *pdev,if (err)return err; -do { -if (!ida_pre_get (&cb710_ida,GFP_KERNEL )) -return -ENOMEM ; - -spin_lock_irqsave (&cb710_ida_lock, flags); - err =ida_get_new (&cb710_ida, &chip->platform_id); -spin_unlock_irqrestore (&cb710_ida_lock, flags); - -if (err && err != -EAGAIN ) -return err; - }while (err); - + err =ida_get_id (&cb710_ida_lock, &cb710_ida, &chip->platform_id); +if (err) +return err;dev_info (&pdev->dev,"id %d, IO 0x%p, IRQ %d\n" , chip->platform_id, chip->iobase, pdev->irq);
drivers/scsi/sd.c +1 -9
@@ -2580,15 +2580,7 @@ static int sd_probe(struct device *dev)if (!gd) goto out_free; -do { -if (!ida_pre_get (&sd_index_ida,GFP_KERNEL )) - goto out_put; - -spin_lock (&sd_index_lock); - error =ida_get_new (&sd_index_ida, &index); -spin_unlock (&sd_index_lock); - }while (error == -EAGAIN ); - + error =ida_get_id (&sd_index_lock, &sd_index_ida, &index);if (error) goto out_put;
drivers/staging/iio/iio.h +0 -1
@@ -426,6 +426,5 @@ static inline bool iio_ring_enabled(struct iio_dev *dev_info)struct ida ; -int iio_get_new_ida_val (struct ida *this_ida);void iio_free_ida_val (struct ida *this_ida,int id);#endif /* _INDUSTRIAL_IO_H_ */
drivers/staging/iio/industrialio-core.c +4 -34
@@ -250,15 +250,8 @@ int iio_device_get_chrdev_minor(void) {int ret, val; -ida_again: -if (unlikely (ida_pre_get (&iio_chrdev_ida,GFP_KERNEL ) ==0 )) -return -ENOMEM ; -spin_lock (&iio_ida_lock); - ret =ida_get_new (&iio_chrdev_ida, &val); -spin_unlock (&iio_ida_lock); -if (unlikely (ret == -EAGAIN )) - goto ida_again; -else if (unlikely (ret)) + ret =ida_get_id (&iio_ida_lock, &iio_chrdev_ida, &val); +if (ret <0 )return ret;if (val >IIO_DEV_MAX )return -ENOMEM ;
@@ -794,28 +787,6 @@ static void iio_device_unregister_sysfs(struct iio_dev *dev_info)sysfs_remove_group (&dev_info->dev.kobj, dev_info->info->attrs); } -/* Return a negative errno on failure */ -int iio_get_new_ida_val (struct ida *this_ida) -{ -int ret; -int val; - -ida_again: -if (unlikely (ida_pre_get (this_ida,GFP_KERNEL ) ==0 )) -return -ENOMEM ; - -spin_lock (&iio_ida_lock); - ret =ida_get_new (this_ida, &val); -spin_unlock (&iio_ida_lock); -if (unlikely (ret == -EAGAIN )) - goto ida_again; -else if (unlikely (ret)) -return ret; - -return val; -} -EXPORT_SYMBOL (iio_get_new_ida_val); -void iio_free_ida_val (struct ida *this_ida,int id) {spin_lock (&iio_ida_lock);
@@ -1179,9 +1150,8 @@ int iio_device_register(struct iio_dev *dev_info) {int ret; - dev_info->id =iio_get_new_ida_val (&iio_ida); -if (dev_info->id <0 ) { - ret = dev_info->id; + ret =ida_get_id (&iio_ida_lock, &iio_ida, &dev_info->id); +if (ret <0 ) {dev_err (&dev_info->dev,"Failed to get id\n" ); goto error_ret; }
drivers/staging/iio/industrialio-trigger.c +13 -52
100 lines not on this page · raw message
include/linux/idr.h +1 -0
@@ -147,5 +147,6 @@ void ida_destroy(struct ida *ida);void ida_init (struct ida *ida);void __init idr_init_cache (void ); +int ida_get_id (spinlock_t *lock,struct ida *ida,int *val);#endif /* __IDR_H__ */
lib/idr.c +20 -0
@@ -939,3 +939,23 @@ void ida_init(struct ida *ida) }EXPORT_SYMBOL (ida_init); + +int ida_get_id (spinlock_t *lock,struct ida *ida,int *val) +{ +int ret =0 ; +ida_again: +if (unlikely (ida_pre_get (ida,GFP_KERNEL ) ==0 )) +return -ENOMEM ; + +spin_lock (lock); + ret =ida_get_new (ida, val); +spin_unlock (lock); + +if (unlikely (ret == -EAGAIN )) + goto ida_again; +else if (likely (!ret)) + *val = *val &MAX_ID_MASK ; + +return ret; +} +EXPORT_SYMBOL (ida_get_id);
Signature · 1 line
1.7.3.4
On Jul 13 Jonathan Cameron wrote at LKML:
[...]
Quoted 11 lines
Taking ida's first, how about the following patch? I'm not at all attached to the form it takes, merely to cutting out on the cut and paste.
Note I've done only a few random places. There aren't that many ida users and I've only played with that for now.
Remaining ida cases:
drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c: (cleans up in case of out of range)drivers/scsi/osd/osd_uld.c: (locks not taken)
[...]
Boaz, Benny,
osd_uld.c::osd_minor_ida is accessed unsafely.
Device probe() and remove() methods are not globally serialized.
Signature · 3 lines
Stefan Richter -=====-==-== -=== -==-= http://arcgraph.de/sr/
Quoted 11 lines · Stefan Richter
On Jul 13 Jonathan Cameron wrote at LKML:
[...]Quoted 9 lines
Taking ida's first, how about the following patch? I'm not at all attached to the form it takes, merely to cutting out on the cut and paste.
Note I've done only a few random places. There aren't that many ida users and I've only played with that for now.
Remaining ida cases:
Quoted 8 lines
Quoted 2 lines
drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c: (cleans up in case of out of range)drivers/scsi/osd/osd_uld.c: (locks not taken)[...]
Boaz, Benny,
osd_uld.c::osd_minor_idais accessed unsafely.
Deviceprobe()andremove()methods are not globally serialized.
Sorry for the delay. Vacation
Thanks Stefan I'll look into it. I remember I thought about it and tested it at the time, but I might be wrong. I'll look into it.
Thanks
Boaz
Quoted 9 lines · On Jul 15 Boaz Harrosh wrote:
Quoted 2 lines · Stefan Richter
osd_uld.c::osd_minor_idais accessed unsafely.
Deviceprobe()andremove()methods are not globally serialized.Sorry for the delay. Vacation
Thanks Stefan I'll look into it. I remember I thought about it and tested it at the time, but I might be wrong. I'll look into it.
Could actually be that there was or even still is some degree of serialization by the SCSI core in typical usage. But I think the general case is nowadays fully concurrent. E.g.
echo $name > /sys/bus/scsi/drivers/osd*/{,un}bind
if issued in parallel for different device names. Though it is probably borderline impossible to actually hit a concurrent osd_minor_ida access on purpose.
Signature · 3 lines
Stefan Richter -=====-==-== -=== -==== http://arcgraph.de/sr/
Quoted 3 lines · On Jul 13 Jonathan Cameron wrote:
Taking ida's first, how about the following patch? I'm not at all attached to the form it takes, merely to cutting out on the cut and paste.
Not a big-picture opinion here whether this is a good thing; only some small comments on side issues:
[...]
Quoted 2 lines
The other thing this highlights is that I suspect quite a few are protected by spin locks when a mutex would be fine. Hence that might be worth tidying up first.
It seems to be the other way around in this case: Why use a mutex if a spinlock is fine?
[...]
Quoted 14 lines
drivers/misc/cb710/core.c +0
-8@@ -254,18 +254,9 @@ static int __devinit cb710_probe(struct pci_dev *pdev,if (err)return err; - do { - if (!ida_pre_get(&cb710_ida, GFP_KERNEL)) - return -ENOMEM; - - spin_lock_irqsave(&cb710_ida_lock, flags); - err = ida_get_new(&cb710_ida, &chip->platform_id); - spin_unlock_irqrestore(&cb710_ida_lock, flags); -
drivers/misc/cb710/core.c static int __devinit cb710_probe(struct pci_dev *pdev, · line 262
Quoted 10 lines
drivers/misc/cb710/core.c +3
-4-if (err && err != -EAGAIN ) -return err; - }while (err); - + err =ida_get_id (&cb710_ida_lock, &cb710_ida, &chip->platform_id); +if (err) +return err;dev_info (&pdev->dev,"id %d, IO 0x%p, IRQ %d\n" , chip->platform_id, chip->iobase, pdev->irq);
To balance this change to cb710_probe, also switch from spin_lock_irqsave/ spin_unlock_irqrestore to spin_lock/spin_unlock in cb710_remove_one for clarity.
[...]
Quoted 16 lines
lib/idr.c +10
-0@@ -939,3 +939,23 @@ void ida_init(struct ida *ida) }EXPORT_SYMBOL (ida_init); + +int ida_get_id (spinlock_t *lock,struct ida *ida,int *val) +{ +int ret =0 ; +ida_again: +if (unlikely (ida_pre_get (ida,GFP_KERNEL ) ==0 )) +return -ENOMEM ; + +spin_lock (lock); + ret =ida_get_new (ida, val);
lib/idr.c void ida_init(struct ida *ida) · line 961
Quoted 10 lines
lib/idr.c +10
-0+spin_unlock (lock); + +if (unlikely (ret == -EAGAIN )) + goto ida_again; +else if (likely (!ret)) + *val = *val &MAX_ID_MASK ; + +return ret; +} +EXPORT_SYMBOL (ida_get_id);
A new exported function (in lib/ even) should come with a kerneldoc comment of course. Here it is among else noteworthy that the caller must provide GFP_KERNEL allocations capable context and that @lock cannot be shared with users in IRQ or softIRQ contexts.
Signature · 3 lines
Stefan Richter -=====-==-== -=== -==-= http://arcgraph.de/sr/
Quoted 38 lines · Stefan Richter
Quoted 3 lines · On Jul 13 Jonathan Cameron wrote:
Taking ida's first, how about the following patch? I'm not at all attached to the form it takes, merely to cutting out on the cut and paste.
Not a big-picture opinion here whether this is a good thing; only some small comments on side issues:
[...]
Quoted 2 lines
The other thing this highlights is that I suspect quite a few are protected by spin locks when a mutex would be fine. Hence that might be worth tidying up first.
It seems to be the other way around in this case: Why use a mutex if a spinlock is fine?
[...]
Quoted 22 lines
drivers/misc/cb710/core.c +3
-12@@ -254,18 +254,9 @@ static int __devinit cb710_probe(struct pci_dev *pdev,if (err)return err; -do { -if (!ida_pre_get (&cb710_ida,GFP_KERNEL )) -return -ENOMEM ; - -spin_lock_irqsave (&cb710_ida_lock, flags); - err =ida_get_new (&cb710_ida, &chip->platform_id); -spin_unlock_irqrestore (&cb710_ida_lock, flags); - -if (err && err != -EAGAIN ) -return err; - }while (err); - + err =ida_get_id (&cb710_ida_lock, &cb710_ida, &chip->platform_id); +if (err) +return err;
Quoted 6 lines
drivers/misc/cb710/core.c static int __devinit cb710_probe(struct pci_dev *pdev, · line 262
Quoted 2 lines
drivers/misc/cb710/core.c +0
-0dev_info (&pdev->dev,"id %d, IO 0x%p, IRQ %d\n" , chip->platform_id, chip->iobase, pdev->irq);To balance this change to
cb710_probe, also switch from spin_lock_irqsave/spin_unlock_irqrestoreto spin_lock/spin_unlock incb710_remove_onefor clarity.
Good point. I'd actually suggest adding a paired release_id function with similar semantics to the get function just to keep things consistent.
Quoted 25 lines
[...]
Quoted 23 lines
lib/idr.c +17
-0@@ -939,3 +939,23 @@ void ida_init(struct ida *ida) }EXPORT_SYMBOL (ida_init); + +int ida_get_id (spinlock_t *lock,struct ida *ida,int *val) +{ +int ret =0 ; +ida_again: +if (unlikely (ida_pre_get (ida,GFP_KERNEL ) ==0 )) +return -ENOMEM ; + +spin_lock (lock); + ret =ida_get_new (ida, val); +spin_unlock (lock); + +if (unlikely (ret == -EAGAIN )) + goto ida_again; +else if (likely (!ret)) + *val = *val &MAX_ID_MASK ; +
Quoted 8 lines
lib/idr.c void ida_init(struct ida *ida) · line 961
Quoted 3 lines
lib/idr.c +3
-0+return ret; +} +EXPORT_SYMBOL (ida_get_id);A new exported function (in
lib/even) should come with a kerneldoc comment of course. Here it is among else noteworthy that the caller must provideGFP_KERNELallocations capable context and that @lock cannot be shared with users in IRQ or softIRQ contexts.
Of course, I was just being lazy for an RFC ;) Is suspect any formal submission will need a few iterations before everyone is happy.
(cc'ing Rusty Russell)
Hello,
Quoted 7 lines · Jonathan Cameron
The other thing this highlights is that I suspect quite a few are protected by spin locks when a mutex would be fine. Hence that might be worth tidying up first.
Anyhow, a cleanup worth making? (obviously the exact form needs some work, but I think the following is enough to start a discussion!)
Subject: [PATCH] ida utility function
Rusty suggested similar addition some weeks ago, so people are really getting annoyed by this.
http://thread.gmane.org/gmane.linux.kernel/1148513/focus=74236
Here's an interface that I think should work,
int ida_get(struct ida *ida, int begin, int end, gfp_t gfp);
It uses an internal spinlock, returns the allocated ID and @end <= 0 indicates no limit.
Thanks.
Signature · 1 line
tejun
Quoted 15 lines · Tejun Heo
(cc'ing Rusty Russell)
Hello,Quoted 7 lines · Jonathan Cameron
The other thing this highlights is that I suspect quite a few are protected by spin locks when a mutex would be fine. Hence that might be worth tidying up first.
Anyhow, a cleanup worth making? (obviously the exact form needs some work, but I think the following is enough to start a discussion!)
Subject: [PATCH] ida utility function
Rusty suggested similar addition some weeks ago, so people are really getting annoyed by this.
Quoted 8 lines
http://thread.gmane.org/gmane.linux.kernel/1148513/focus=74236
Here's an interface that I think should work,
int ida_get(struct ida *ida, int begin, int end, gfp_t gfp);It uses an internal spinlock, returns the allocated ID and @end <= 0 indicates no limit.
Cool.
Rusty, are you pursuing this? Approach looks sensible to me.
Quoted 1 line · Jonathan Cameron
Rusty, are you pursuing this? Approach looks sensible to me.
OK, I'll polish up what I had based on Tejun's feedback and repost.
Thanks for the prod...
Rusty.
Quoted 9 lines · Jonathan Cameron
Quoted 6 lines
Here's an interface that I think should work,
int ida_get(struct ida *ida, int begin, int end, gfp_t gfp);It uses an internal spinlock, returns the allocated ID and @end <= 0 indicates no limit.
Cool.
Rusty, are you pursuing this? Approach looks sensible to me.
Yep, here's my latest version. Feel free to run with it, or not.
Thanks!
Rusty.
From: Rusty Russell <[email protected]>
Subject: ida: Simplified functions for id allocation.
The current hyper-optimized functions are overkill if you simply want to allocate an id for a device. Create versions which use an internal lock.
Thanks to Tejun for feedback. Feel free to delete the #ifdef TEST code.
--- include/linux/idr.h | 4 + lib/idr.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+)
include/linux/idr.h +4 -0
@@ -146,6 +146,10 @@ void ida_remove(struct ida *ida, int id)void ida_destroy (struct ida *ida);void ida_init (struct ida *ida); +int ida_simple_get (struct ida *ida,unsigned int start,unsigned int end, +gfp_t gfp_mask); +void ida_simple_remove (struct ida *ida,unsigned int id); +void __init idr_init_cache (void );#endif /* __IDR_H__ */
lib/idr.c +116 -0
130 lines not on this page · raw message
Tejun Heo
Acked-byQuoted 11 lines · Rusty Russell
From: Rusty Russell <[email protected]>
Subject: ida: Simplified functions for id allocation.The current hyper-optimized functions are overkill if you simply want to allocate an id for a device. Create versions which use an internal lock.
Thanks to Tejun for feedback. Feel free to delete the #ifdef TEST code.
Signed-off-by Rusty Russell <[email protected]>
...
Quoted 2 lines
static struct
kmem_cache*idr_layer_cache;
+staticDEFINE_SPINLOCK(simple_ida);
I think the name is a bit confusing. Maybe simple_ida_lock is better? Other than that,
I guess this is best routed through -mm?
Thanks.
Signature · 1 line
tejun
Jonathan Cameron
Acked-byQuoted 16 lines · Tejun Heo
Quoted 11 lines · Rusty Russell
From: Rusty Russell <[email protected]>
Subject: ida: Simplified functions for id allocation.The current hyper-optimized functions are overkill if you simply want to allocate an id for a device. Create versions which use an internal lock.
Thanks to Tejun for feedback. Feel free to delete the #ifdef TEST code.
Signed-off-by Rusty Russell <[email protected]>...
Quoted 2 lines
static struct
kmem_cache*idr_layer_cache;
+staticDEFINE_SPINLOCK(simple_ida);
Quoted 9 lines
I think the name is a bit confusing. Maybe
simple_ida_lockis better? Other than that,Acked-by Tejun Heo <[email protected]>I guess this is best routed through -mm?
Thanks.
Thanks Rusty. Just what I was looking for. I'll push out some patches using this once it's picked up.
Quoted 11 lines · Tejun Heo
Quoted 10 lines · Rusty Russell
From: Rusty Russell <[email protected]>
Subject: ida: Simplified functions for id allocation.The current hyper-optimized functions are overkill if you simply want to allocate an id for a device. Create versions which use an internal lock.
Thanks to Tejun for feedback. Feel free to delete the #ifdef TEST code.
Quoted 7 lines
Quoted 1 line
Signed-off-by Rusty Russell <[email protected]>...
Quoted 2 lines
static struct
kmem_cache*idr_layer_cache;
+staticDEFINE_SPINLOCK(simple_ida);I think the name is a bit confusing. Maybe
simple_ida_lockis better? Other than that,
Ooh, one more thing, maybe it would be better to use spin_lock_irq() to allow calling free under other irq locks.
Thanks.
Signature · 1 line
tejun
Quoted 14 lines · Tejun Heo
Quoted 13 lines · Tejun Heo
Quoted 11 lines · Rusty Russell
From: Rusty Russell <[email protected]>
Subject: ida: Simplified functions for id allocation.The current hyper-optimized functions are overkill if you simply want to allocate an id for a device. Create versions which use an internal lock.
Thanks to Tejun for feedback. Feel free to delete the #ifdef TEST code.
Signed-off-by Rusty Russell <[email protected]>...
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
static struct
kmem_cache*idr_layer_cache;
+staticDEFINE_SPINLOCK(simple_ida);I think the name is a bit confusing. Maybe
simple_ida_lockis better? Other than that,Ooh, one more thing, maybe it would be better to use
spin_lock_irq()to allow calling free under other irq locks.
Jonathan, please take original patch and mod it to taste, and produce a series on it you can push to Andrew.
As for irqsave etc, as soon as someone needs that we can add it... Jonathan will run into it soon enough.
Thanks,
Rusty.
Quoted 24 lines · Rusty Russell
Quoted 14 lines · Tejun Heo
Quoted 13 lines · Tejun Heo
Quoted 11 lines · Rusty Russell
From: Rusty Russell <[email protected]>
Subject: ida: Simplified functions for id allocation.The current hyper-optimized functions are overkill if you simply want to allocate an id for a device. Create versions which use an internal lock.
Thanks to Tejun for feedback. Feel free to delete the #ifdef TEST code.
Signed-off-by Rusty Russell <[email protected]>...
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
static struct
kmem_cache*idr_layer_cache;
+staticDEFINE_SPINLOCK(simple_ida);I think the name is a bit confusing. Maybe
simple_ida_lockis better? Other than that,Ooh, one more thing, maybe it would be better to use
spin_lock_irq()to allow calling free under other irq locks.
Quoted 9 lines
Jonathan, please take original patch and mod it to taste, and produce a series on it you can push to Andrew.
As for irqsave etc, as soon as someone needs that we can add it... Jonathan will run into it soon enough.
Thanks,
Rusty.
Given the timing, it's clearly 3.2 merge window material anyway. Too late to push any users this time round even if we hustled it through.
Quite a few 'interesting' users out there now I look into them. Might take a little while to get them past the relevant maintainers.
I've just sent out a few of the simpler cases. I guess Andrew may take the core patch and the others will route through relevant subsystems.
A few more to do. Some of them need a little more thought.
Jonathan