--- zzzz-none-000/linux-3.10.107/drivers/char/misc.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/char/misc.c 2021-02-04 17:41:59.000000000 +0000 @@ -114,17 +114,17 @@ int minor = iminor(inode); struct miscdevice *c; int err = -ENODEV; - const struct file_operations *old_fops, *new_fops = NULL; + const struct file_operations *new_fops = NULL; mutex_lock(&misc_mtx); - + list_for_each_entry(c, &misc_list, list) { if (c->minor == minor) { - new_fops = fops_get(c->fops); + new_fops = fops_get(c->fops); break; } } - + if (!new_fops) { mutex_unlock(&misc_mtx); request_module("char-major-%d-%d", MISC_MAJOR, minor); @@ -140,18 +140,17 @@ goto fail; } + /* + * Place the miscdevice in the file's + * private_data so it can be used by the + * file operations, including f_op->open below + */ + file->private_data = c; + err = 0; - old_fops = file->f_op; - file->f_op = new_fops; - if (file->f_op->open) { - file->private_data = c; - err=file->f_op->open(inode,file); - if (err) { - fops_put(file->f_op); - file->f_op = fops_get(old_fops); - } - } - fops_put(old_fops); + replace_fops(file, new_fops); + if (file->f_op->open) + err = file->f_op->open(inode,file); fail: mutex_unlock(&misc_mtx); return err; @@ -168,33 +167,36 @@ /** * misc_register - register a miscellaneous device * @misc: device structure - * + * * Register a miscellaneous device with the kernel. If the minor * number is set to %MISC_DYNAMIC_MINOR a minor number is assigned * and placed in the minor field of the structure. For other cases * the minor number requested is used. * * The structure passed is linked into the kernel and may not be - * destroyed until it has been unregistered. + * destroyed until it has been unregistered. By default, an open() + * syscall to the device sets file->private_data to point to the + * structure. Drivers don't need open in fops for this. * * A zero is returned on success and a negative errno code for * failure. */ - + int misc_register(struct miscdevice * misc) { dev_t dev; int err = 0; + bool is_dynamic = (misc->minor == MISC_DYNAMIC_MINOR); INIT_LIST_HEAD(&misc->list); mutex_lock(&misc_mtx); - if (misc->minor == MISC_DYNAMIC_MINOR) { + if (is_dynamic) { int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS); if (i >= DYNAMIC_MINORS) { - mutex_unlock(&misc_mtx); - return -EBUSY; + err = -EBUSY; + goto out; } misc->minor = DYNAMIC_MINORS - i - 1; set_bit(i, misc_minors); @@ -203,20 +205,25 @@ list_for_each_entry(c, &misc_list, list) { if (c->minor == misc->minor) { - mutex_unlock(&misc_mtx); - return -EBUSY; + err = -EBUSY; + goto out; } } } dev = MKDEV(MISC_MAJOR, misc->minor); - misc->this_device = device_create(misc_class, misc->parent, dev, - misc, "%s", misc->name); + misc->this_device = + device_create_with_groups(misc_class, misc->parent, dev, + misc, misc->groups, "%s", misc->name); if (IS_ERR(misc->this_device)) { - int i = DYNAMIC_MINORS - misc->minor - 1; - if (i < DYNAMIC_MINORS && i >= 0) - clear_bit(i, misc_minors); + if (is_dynamic) { + int i = DYNAMIC_MINORS - misc->minor - 1; + + if (i < DYNAMIC_MINORS && i >= 0) + clear_bit(i, misc_minors); + misc->minor = MISC_DYNAMIC_MINOR; + } err = PTR_ERR(misc->this_device); goto out; } @@ -236,17 +243,15 @@ * @misc: device to unregister * * Unregister a miscellaneous device that was previously - * successfully registered with misc_register(). Success - * is indicated by a zero return, a negative errno code - * indicates an error. + * successfully registered with misc_register(). */ -int misc_deregister(struct miscdevice *misc) +void misc_deregister(struct miscdevice *misc) { int i = DYNAMIC_MINORS - misc->minor - 1; if (WARN_ON(list_empty(&misc->list))) - return -EINVAL; + return; mutex_lock(&misc_mtx); list_del(&misc->list); @@ -254,7 +259,6 @@ if (i < DYNAMIC_MINORS && i >= 0) clear_bit(i, misc_minors); mutex_unlock(&misc_mtx); - return 0; } EXPORT_SYMBOL(misc_register); @@ -274,10 +278,9 @@ static int __init misc_init(void) { int err; + struct proc_dir_entry *ret; -#ifdef CONFIG_PROC_FS - proc_create("misc", 0, NULL, &misc_proc_fops); -#endif + ret = proc_create("misc", 0, NULL, &misc_proc_fops); misc_class = class_create(THIS_MODULE, "misc"); err = PTR_ERR(misc_class); if (IS_ERR(misc_class)) @@ -293,7 +296,8 @@ printk("unable to get major %d for misc devices\n", MISC_MAJOR); class_destroy(misc_class); fail_remove: - remove_proc_entry("misc", NULL); + if (ret) + remove_proc_entry("misc", NULL); return err; } subsys_initcall(misc_init);