#include <linux/init.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
-#include <linux/idr.h>
#include <linux/mutex.h>
#include <linux/cdev.h>
#include <linux/poll.h>
#include <linux/pps_kernel.h>
#include <linux/slab.h>
+#include <linux/xarray.h>
#include "kc.h"
static dev_t pps_devt;
static struct class *pps_class;
-static DEFINE_MUTEX(pps_idr_lock);
-static DEFINE_IDR(pps_idr);
+static DEFINE_XARRAY_ALLOC(pps_devs);
/*
* Char device methods
/* Now we can release the ID for re-use */
pr_debug("deallocating pps%d\n", pps->id);
- mutex_lock(&pps_idr_lock);
- idr_remove(&pps_idr, pps->id);
- mutex_unlock(&pps_idr_lock);
+ xa_erase(&pps_devs, pps->id);
kfree(dev);
kfree(pps);
int err;
dev_t devt;
- mutex_lock(&pps_idr_lock);
/*
- * Get new ID for the new PPS source. After idr_alloc() calling
- * the new source will be freely available into the kernel.
+ * Get new ID for the new PPS source. After this call
+ * the new source will be freely available in the kernel.
*/
- err = idr_alloc(&pps_idr, pps, 0, PPS_MAX_SOURCES, GFP_KERNEL);
+ err = xa_alloc(&pps_devs, &pps->id, pps,
+ XA_LIMIT(0, PPS_MAX_SOURCES - 1), GFP_KERNEL);
if (err < 0) {
- if (err == -ENOSPC) {
+ if (err == -EBUSY) {
pr_err("%s: too many PPS sources in the system\n",
pps->info.name);
- err = -EBUSY;
}
- goto out_unlock;
+ goto out;
}
- pps->id = err;
- mutex_unlock(&pps_idr_lock);
devt = MKDEV(MAJOR(pps_devt), pps->id);
if (err) {
pr_err("%s: failed to add char device %d:%d\n",
pps->info.name, MAJOR(pps_devt), pps->id);
- goto free_idr;
+ goto erase;
}
pps->dev = device_create(pps_class, pps->info.dev, devt, pps,
"pps%d", pps->id);
del_cdev:
cdev_del(&pps->cdev);
-
-free_idr:
- mutex_lock(&pps_idr_lock);
- idr_remove(&pps_idr, pps->id);
-out_unlock:
- mutex_unlock(&pps_idr_lock);
+erase:
+ xa_erase(&pps_devs, pps->id);
+out:
return err;
}
*
* The cookie is automatically set to NULL in pps_unregister_source()
* so that it will not be used again, even if the pps device cannot
- * be removed from the idr due to pending references holding the minor
+ * be removed from the array due to pending references holding the minor
* number in use.
*/
struct pps_device *pps_lookup_dev(void const *cookie)
{
struct pps_device *pps;
- unsigned id;
+ unsigned long id;
- rcu_read_lock();
- idr_for_each_entry(&pps_idr, pps, id)
+ xa_for_each(&pps_devs, id, pps)
if (cookie == pps->lookup_cookie)
break;
- rcu_read_unlock();
return pps;
}
EXPORT_SYMBOL(pps_lookup_dev);