mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
misc: misc_minor_alloc to use ida for all dynamic/misc dynamic minors
misc_minor_alloc was allocating id using ida for minor only in case of
MISC_DYNAMIC_MINOR but misc_minor_free was always freeing ids
using ida_free causing a mismatch and following warn:
> > WARNING: CPU: 0 PID: 159 at lib/idr.c:525 ida_free+0x3e0/0x41f
> > ida_free called for id=127 which is not allocated.
> > <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
...
> > [<60941eb4>] ida_free+0x3e0/0x41f
> > [<605ac993>] misc_minor_free+0x3e/0xbc
> > [<605acb82>] misc_deregister+0x171/0x1b3
misc_minor_alloc is changed to allocate id from ida for all minors
falling in the range of dynamic/ misc dynamic minors
Fixes: ab760791c0
("char: misc: Increase the maximum number of dynamic misc devices to 1048448")
Signed-off-by: Vimal Agrawal <vimal.agrawal@sophos.com>
Reviewed-by: Dirk VanDerMerwe <dirk.vandermerwe@sophos.com>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20241021133812.23703-1-vimal.agrawal@sophos.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
567a311d0a
commit
6d04d2b554
1 changed files with 29 additions and 8 deletions
|
@ -63,16 +63,30 @@ static DEFINE_MUTEX(misc_mtx);
|
|||
#define DYNAMIC_MINORS 128 /* like dynamic majors */
|
||||
static DEFINE_IDA(misc_minors_ida);
|
||||
|
||||
static int misc_minor_alloc(void)
|
||||
static int misc_minor_alloc(int minor)
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
ret = ida_alloc_max(&misc_minors_ida, DYNAMIC_MINORS - 1, GFP_KERNEL);
|
||||
if (ret >= 0) {
|
||||
ret = DYNAMIC_MINORS - ret - 1;
|
||||
if (minor == MISC_DYNAMIC_MINOR) {
|
||||
/* allocate free id */
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
ret = ida_alloc_range(&misc_minors_ida, MISC_DYNAMIC_MINOR + 1,
|
||||
MINORMASK, GFP_KERNEL);
|
||||
/* specific minor, check if it is in dynamic or misc dynamic range */
|
||||
if (minor < DYNAMIC_MINORS) {
|
||||
minor = DYNAMIC_MINORS - minor - 1;
|
||||
ret = ida_alloc_range(&misc_minors_ida, minor, minor, GFP_KERNEL);
|
||||
} else if (minor > MISC_DYNAMIC_MINOR) {
|
||||
ret = ida_alloc_range(&misc_minors_ida, minor, minor, GFP_KERNEL);
|
||||
} else {
|
||||
/* case of non-dynamic minors, no need to allocate id */
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -219,7 +233,7 @@ int misc_register(struct miscdevice *misc)
|
|||
mutex_lock(&misc_mtx);
|
||||
|
||||
if (is_dynamic) {
|
||||
int i = misc_minor_alloc();
|
||||
int i = misc_minor_alloc(misc->minor);
|
||||
|
||||
if (i < 0) {
|
||||
err = -EBUSY;
|
||||
|
@ -228,6 +242,7 @@ int misc_register(struct miscdevice *misc)
|
|||
misc->minor = i;
|
||||
} else {
|
||||
struct miscdevice *c;
|
||||
int i;
|
||||
|
||||
list_for_each_entry(c, &misc_list, list) {
|
||||
if (c->minor == misc->minor) {
|
||||
|
@ -235,6 +250,12 @@ int misc_register(struct miscdevice *misc)
|
|||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
i = misc_minor_alloc(misc->minor);
|
||||
if (i < 0) {
|
||||
err = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
dev = MKDEV(MISC_MAJOR, misc->minor);
|
||||
|
|
Loading…
Add table
Reference in a new issue