Merge tag 'driver-core-6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / drivers / char / misc.c
index cba19bfdc44ddb5c082e681d7526dce723b43ac6..7a1388b0572b9941e0be4c56c3170e1ca527c71c 100644 (file)
@@ -61,7 +61,29 @@ static DEFINE_MUTEX(misc_mtx);
  * Assigned numbers, used for dynamic minors
  */
 #define DYNAMIC_MINORS 128 /* like dynamic majors */
-static DECLARE_BITMAP(misc_minors, DYNAMIC_MINORS);
+static DEFINE_IDA(misc_minors_ida);
+
+static int misc_minor_alloc(void)
+{
+       int ret;
+
+       ret = ida_alloc_max(&misc_minors_ida, DYNAMIC_MINORS - 1, GFP_KERNEL);
+       if (ret >= 0) {
+               ret = DYNAMIC_MINORS - ret - 1;
+       } else {
+               ret = ida_alloc_range(&misc_minors_ida, MISC_DYNAMIC_MINOR + 1,
+                                     MINORMASK, GFP_KERNEL);
+       }
+       return ret;
+}
+
+static void misc_minor_free(int minor)
+{
+       if (minor < DYNAMIC_MINORS)
+               ida_free(&misc_minors_ida, DYNAMIC_MINORS - minor - 1);
+       else if (minor > MISC_DYNAMIC_MINOR)
+               ida_free(&misc_minors_ida, minor);
+}
 
 #ifdef CONFIG_PROC_FS
 static void *misc_seq_start(struct seq_file *seq, loff_t *pos)
@@ -183,14 +205,13 @@ int misc_register(struct miscdevice *misc)
        mutex_lock(&misc_mtx);
 
        if (is_dynamic) {
-               int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS);
+               int i = misc_minor_alloc();
 
-               if (i >= DYNAMIC_MINORS) {
+               if (i < 0) {
                        err = -EBUSY;
                        goto out;
                }
-               misc->minor = DYNAMIC_MINORS - i - 1;
-               set_bit(i, misc_minors);
+               misc->minor = i;
        } else {
                struct miscdevice *c;
 
@@ -209,10 +230,7 @@ int misc_register(struct miscdevice *misc)
                                          misc, misc->groups, "%s", misc->name);
        if (IS_ERR(misc->this_device)) {
                if (is_dynamic) {
-                       int i = DYNAMIC_MINORS - misc->minor - 1;
-
-                       if (i < DYNAMIC_MINORS && i >= 0)
-                               clear_bit(i, misc_minors);
+                       misc_minor_free(misc->minor);
                        misc->minor = MISC_DYNAMIC_MINOR;
                }
                err = PTR_ERR(misc->this_device);
@@ -240,23 +258,20 @@ EXPORT_SYMBOL(misc_register);
 
 void misc_deregister(struct miscdevice *misc)
 {
-       int i = DYNAMIC_MINORS - misc->minor - 1;
-
        if (WARN_ON(list_empty(&misc->list)))
                return;
 
        mutex_lock(&misc_mtx);
        list_del(&misc->list);
        device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor));
-       if (i < DYNAMIC_MINORS && i >= 0)
-               clear_bit(i, misc_minors);
+       misc_minor_free(misc->minor);
        mutex_unlock(&misc_mtx);
 }
 EXPORT_SYMBOL(misc_deregister);
 
-static char *misc_devnode(struct device *dev, umode_t *mode)
+static char *misc_devnode(const struct device *dev, umode_t *mode)
 {
-       struct miscdevice *c = dev_get_drvdata(dev);
+       const struct miscdevice *c = dev_get_drvdata(dev);
 
        if (mode && c->mode)
                *mode = c->mode;