diff options
Diffstat (limited to 'drivers/char/misc.c')
| -rw-r--r-- | drivers/char/misc.c | 45 | 
1 files changed, 30 insertions, 15 deletions
diff --git a/drivers/char/misc.c b/drivers/char/misc.c index cba19bfdc44d..7a1388b0572b 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -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;  | 
