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

[media] lirc: use refcounting for lirc devices

If a lirc device is unplugged, the struct rc_dev is freed even though
userspace can still have a file descriptor open on the lirc chardev. The
rc_dev structure can be used in a subsequent, or even currently executing
ioctl, read or write.

Signed-off-by: Sean Young <sean@mess.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>

authored by

Sean Young and committed by
Mauro Carvalho Chehab
74c839b2 069f3b10

+52 -70
+52 -70
drivers/media/rc/lirc_dev.c
··· 54 54 struct lirc_buffer *buf; 55 55 unsigned int chunk_size; 56 56 57 - struct cdev *cdev; 57 + struct device dev; 58 + struct cdev cdev; 58 59 59 60 struct task_struct *task; 60 61 long jiffies_to_wait; ··· 77 76 ir->d.minor = NOPLUG; 78 77 } 79 78 80 - static void lirc_irctl_cleanup(struct irctl *ir) 79 + static void lirc_release(struct device *ld) 81 80 { 82 - device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor)); 81 + struct irctl *ir = container_of(ld, struct irctl, dev); 82 + 83 + put_device(ir->dev.parent); 83 84 84 85 if (ir->buf != ir->d.rbuf) { 85 86 lirc_buffer_free(ir->buf); 86 87 kfree(ir->buf); 87 88 } 88 - ir->buf = NULL; 89 + 90 + mutex_lock(&lirc_dev_lock); 91 + irctls[ir->d.minor] = NULL; 92 + mutex_unlock(&lirc_dev_lock); 93 + kfree(ir); 89 94 } 90 95 91 96 /* helper function ··· 164 157 struct cdev *cdev; 165 158 int retval; 166 159 167 - cdev = cdev_alloc(); 168 - if (!cdev) 169 - return -ENOMEM; 160 + cdev = &ir->cdev; 170 161 171 162 if (d->fops) { 172 - cdev->ops = d->fops; 163 + cdev_init(cdev, d->fops); 173 164 cdev->owner = d->owner; 174 165 } else { 175 - cdev->ops = &lirc_dev_fops; 166 + cdev_init(cdev, &lirc_dev_fops); 176 167 cdev->owner = THIS_MODULE; 177 168 } 178 169 retval = kobject_set_name(&cdev->kobj, "lirc%d", d->minor); 179 170 if (retval) 180 - goto err_out; 171 + return retval; 181 172 182 - retval = cdev_add(cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1); 183 - if (retval) 184 - goto err_out; 185 - 186 - ir->cdev = cdev; 187 - 188 - return 0; 189 - 190 - err_out: 191 - cdev_del(cdev); 192 - return retval; 173 + cdev->kobj.parent = &ir->dev.kobj; 174 + return cdev_add(cdev, ir->dev.devt, 1); 193 175 } 194 176 195 177 static int lirc_allocate_buffer(struct irctl *ir) ··· 300 304 301 305 ir->d = *d; 302 306 303 - device_create(lirc_class, ir->d.dev, 304 - MKDEV(MAJOR(lirc_base_dev), ir->d.minor), NULL, 305 - "lirc%u", ir->d.minor); 307 + ir->dev.devt = MKDEV(MAJOR(lirc_base_dev), ir->d.minor); 308 + ir->dev.class = lirc_class; 309 + ir->dev.parent = d->dev; 310 + ir->dev.release = lirc_release; 311 + dev_set_name(&ir->dev, "lirc%d", ir->d.minor); 312 + device_initialize(&ir->dev); 306 313 307 314 if (d->sample_rate) { 308 315 ir->jiffies_to_wait = HZ / d->sample_rate; ··· 328 329 goto out_sysfs; 329 330 330 331 ir->attached = 1; 332 + 333 + err = device_add(&ir->dev); 334 + if (err) 335 + goto out_cdev; 336 + 331 337 mutex_unlock(&lirc_dev_lock); 338 + 339 + get_device(ir->dev.parent); 332 340 333 341 dev_info(ir->d.dev, "lirc_dev: driver %s registered at minor = %d\n", 334 342 ir->d.name, ir->d.minor); 335 343 return minor; 336 - 344 + out_cdev: 345 + cdev_del(&ir->cdev); 337 346 out_sysfs: 338 - device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor)); 347 + put_device(&ir->dev); 339 348 out_lock: 340 349 mutex_unlock(&lirc_dev_lock); 341 350 ··· 371 364 int lirc_unregister_driver(int minor) 372 365 { 373 366 struct irctl *ir; 374 - struct cdev *cdev; 375 367 376 368 if (minor < 0 || minor >= MAX_IRCTL_DEVICES) { 377 369 pr_err("minor (%d) must be between 0 and %d!\n", ··· 383 377 pr_err("failed to get irctl\n"); 384 378 return -ENOENT; 385 379 } 386 - 387 - cdev = ir->cdev; 388 380 389 381 mutex_lock(&lirc_dev_lock); 390 382 ··· 405 401 dev_dbg(ir->d.dev, LOGHEAD "releasing opened driver\n", 406 402 ir->d.name, ir->d.minor); 407 403 wake_up_interruptible(&ir->buf->wait_poll); 408 - mutex_lock(&ir->irctl_lock); 409 - 410 - if (ir->d.set_use_dec) 411 - ir->d.set_use_dec(ir->d.data); 412 - 413 - module_put(cdev->owner); 414 - mutex_unlock(&ir->irctl_lock); 415 - } else { 416 - lirc_irctl_cleanup(ir); 417 - cdev_del(cdev); 418 - kfree(ir); 419 - irctls[minor] = NULL; 420 404 } 421 405 406 + mutex_lock(&ir->irctl_lock); 407 + 408 + if (ir->d.set_use_dec) 409 + ir->d.set_use_dec(ir->d.data); 410 + 411 + mutex_unlock(&ir->irctl_lock); 422 412 mutex_unlock(&lirc_dev_lock); 413 + 414 + device_del(&ir->dev); 415 + cdev_del(&ir->cdev); 416 + put_device(&ir->dev); 423 417 424 418 return 0; 425 419 } ··· 426 424 int lirc_dev_fop_open(struct inode *inode, struct file *file) 427 425 { 428 426 struct irctl *ir; 429 - struct cdev *cdev; 430 427 int retval = 0; 431 428 432 429 if (iminor(inode) >= MAX_IRCTL_DEVICES) { ··· 460 459 goto error; 461 460 } 462 461 463 - cdev = ir->cdev; 464 - if (try_module_get(cdev->owner)) { 465 - ir->open++; 466 - if (ir->d.set_use_inc) 467 - retval = ir->d.set_use_inc(ir->d.data); 468 - 469 - if (retval) { 470 - module_put(cdev->owner); 471 - ir->open--; 472 - } else if (ir->buf) { 462 + ir->open++; 463 + if (ir->d.set_use_inc) 464 + retval = ir->d.set_use_inc(ir->d.data); 465 + if (retval) { 466 + ir->open--; 467 + } else { 468 + if (ir->buf) 473 469 lirc_buffer_clear(ir->buf); 474 - } 475 470 if (ir->task) 476 471 wake_up_process(ir->task); 477 472 } ··· 484 487 int lirc_dev_fop_close(struct inode *inode, struct file *file) 485 488 { 486 489 struct irctl *ir = irctls[iminor(inode)]; 487 - struct cdev *cdev; 488 490 int ret; 489 491 490 492 if (!ir) { ··· 491 495 return -EINVAL; 492 496 } 493 497 494 - cdev = ir->cdev; 495 - 496 498 ret = mutex_lock_killable(&lirc_dev_lock); 497 499 WARN_ON(ret); 498 500 499 501 rc_close(ir->d.rdev); 500 502 501 503 ir->open--; 502 - if (ir->attached) { 503 - if (ir->d.set_use_dec) 504 - ir->d.set_use_dec(ir->d.data); 505 - module_put(cdev->owner); 506 - } else { 507 - lirc_irctl_cleanup(ir); 508 - cdev_del(cdev); 509 - irctls[ir->d.minor] = NULL; 510 - kfree(ir); 511 - } 512 - 504 + if (ir->d.set_use_dec) 505 + ir->d.set_use_dec(ir->d.data); 513 506 if (!ret) 514 507 mutex_unlock(&lirc_dev_lock); 515 508 ··· 765 780 return retval; 766 781 } 767 782 768 - 769 783 pr_info("IR Remote Control driver registered, major %d\n", 770 784 MAJOR(lirc_base_dev)); 771 785 772 786 return 0; 773 787 } 774 - 775 - 776 788 777 789 static void __exit lirc_dev_exit(void) 778 790 {