Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] lirc_dev: rework storage for cdev data

Fixes an oops when an lirc driver that doesn't provide its own fops is
unplugged while the lirc cdev is open. Tested with lirc_igorplugusb,
with a special thanks to Timo Boettcher for providing the test hardware.

Signed-off-by: Jarod Wilson <jarod@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

authored by

Jarod Wilson and committed by
Mauro Carvalho Chehab
c1cbb702 09c8dd8d

+23 -17
+23 -17
drivers/media/IR/lirc_dev.c
··· 58 58 59 59 struct task_struct *task; 60 60 long jiffies_to_wait; 61 - 62 - struct cdev cdev; 63 61 }; 64 62 65 63 static DEFINE_MUTEX(lirc_dev_lock); 66 64 67 65 static struct irctl *irctls[MAX_IRCTL_DEVICES]; 66 + static struct cdev cdevs[MAX_IRCTL_DEVICES]; 68 67 69 68 /* Only used for sysfs but defined to void otherwise */ 70 69 static struct class *lirc_class; ··· 169 170 { 170 171 int retval; 171 172 struct lirc_driver *d = &ir->d; 173 + struct cdev *cdev = &cdevs[d->minor]; 172 174 173 175 if (d->fops) { 174 - cdev_init(&ir->cdev, d->fops); 175 - ir->cdev.owner = d->owner; 176 + cdev_init(cdev, d->fops); 177 + cdev->owner = d->owner; 176 178 } else { 177 - cdev_init(&ir->cdev, &lirc_dev_fops); 178 - ir->cdev.owner = THIS_MODULE; 179 + cdev_init(cdev, &lirc_dev_fops); 180 + cdev->owner = THIS_MODULE; 179 181 } 180 - kobject_set_name(&ir->cdev.kobj, "lirc%d", d->minor); 182 + kobject_set_name(&cdev->kobj, "lirc%d", d->minor); 181 183 182 - retval = cdev_add(&ir->cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1); 184 + retval = cdev_add(cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1); 183 185 if (retval) 184 - kobject_put(&ir->cdev.kobj); 186 + kobject_put(&cdev->kobj); 185 187 186 188 return retval; 187 189 } ··· 363 363 int lirc_unregister_driver(int minor) 364 364 { 365 365 struct irctl *ir; 366 + struct cdev *cdev; 366 367 367 368 if (minor < 0 || minor >= MAX_IRCTL_DEVICES) { 368 369 printk(KERN_ERR "lirc_dev: %s: minor (%d) must be between " ··· 377 376 "for minor %d!\n", __func__, minor); 378 377 return -ENOENT; 379 378 } 379 + 380 + cdev = &cdevs[minor]; 380 381 381 382 mutex_lock(&lirc_dev_lock); 382 383 ··· 403 400 wake_up_interruptible(&ir->buf->wait_poll); 404 401 mutex_lock(&ir->irctl_lock); 405 402 ir->d.set_use_dec(ir->d.data); 406 - module_put(ir->cdev.owner); 403 + module_put(cdev->owner); 407 404 mutex_unlock(&ir->irctl_lock); 408 405 } else { 409 406 lirc_irctl_cleanup(ir); 410 - cdev_del(&ir->cdev); 407 + cdev_del(cdev); 411 408 kfree(ir); 412 409 irctls[minor] = NULL; 413 410 } ··· 421 418 int lirc_dev_fop_open(struct inode *inode, struct file *file) 422 419 { 423 420 struct irctl *ir; 421 + struct cdev *cdev; 424 422 int retval = 0; 425 423 426 424 if (iminor(inode) >= MAX_IRCTL_DEVICES) { ··· 451 447 goto error; 452 448 } 453 449 454 - if (try_module_get(ir->cdev.owner)) { 455 - ++ir->open; 450 + cdev = &cdevs[iminor(inode)]; 451 + if (try_module_get(cdev->owner)) { 452 + ir->open++; 456 453 retval = ir->d.set_use_inc(ir->d.data); 457 454 458 455 if (retval) { 459 - module_put(ir->cdev.owner); 460 - --ir->open; 456 + module_put(cdev->owner); 457 + ir->open--; 461 458 } else { 462 459 lirc_buffer_clear(ir->buf); 463 460 } ··· 480 475 int lirc_dev_fop_close(struct inode *inode, struct file *file) 481 476 { 482 477 struct irctl *ir = irctls[iminor(inode)]; 478 + struct cdev *cdev = &cdevs[iminor(inode)]; 483 479 484 480 if (!ir) { 485 481 printk(KERN_ERR "%s: called with invalid irctl\n", __func__); ··· 494 488 ir->open--; 495 489 if (ir->attached) { 496 490 ir->d.set_use_dec(ir->d.data); 497 - module_put(ir->cdev.owner); 491 + module_put(cdev->owner); 498 492 } else { 499 493 lirc_irctl_cleanup(ir); 500 - cdev_del(&ir->cdev); 494 + cdev_del(cdev); 501 495 irctls[ir->d.minor] = NULL; 502 496 kfree(ir); 503 497 }