summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLogan Gunthorpe <logang@deltatee.com>2017-03-17 14:48:08 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-03-21 01:44:32 -0400
commit233ed09d7fdacf592ee91e6c97ce5f4364fbe7c0 (patch)
treeec1abd90a11dc298a99374c3e693670d584e6c94
parentd47d88361feea2ce11f39bd70467ffc19a61d2d3 (diff)
chardev: add helper function to register char devs with a struct device
Credit for this patch goes is shared with Dan Williams [1]. I've taken things one step further to make the helper function more useful and clean up calling code. There's a common pattern in the kernel whereby a struct cdev is placed in a structure along side a struct device which manages the life-cycle of both. In the naive approach, the reference counting is broken and the struct device can free everything before the chardev code is entirely released. Many developers have solved this problem by linking the internal kobjs in this fashion: cdev.kobj.parent = &parent_dev.kobj; The cdev code explicitly gets and puts a reference to it's kobj parent. So this seems like it was intended to be used this way. Dmitrty Torokhov first put this in place in 2012 with this commit: 2f0157f char_dev: pin parent kobject and the first instance of the fix was then done in the input subsystem in the following commit: 4a215aa Input: fix use-after-free introduced with dynamic minor changes Subsequently over the years, however, this issue seems to have tripped up multiple developers independently. For example, see these commits: 0d5b7da iio: Prevent race between IIO chardev opening and IIO device (by Lars-Peter Clausen in 2013) ba0ef85 tpm: Fix initialization of the cdev (by Jason Gunthorpe in 2015) 5b28dde [media] media: fix use-after-free in cdev_put() when app exits after driver unbind (by Shauh Khan in 2016) This technique is similarly done in at least 15 places within the kernel and probably should have been done so in another, at least, 5 places. The kobj line also looks very suspect in that one would not expect drivers to have to mess with kobject internals in this way. Even highly experienced kernel developers can be surprised by this code, as seen in [2]. To help alleviate this situation, and hopefully prevent future wasted effort on this problem, this patch introduces a helper function to register a char device along with its parent struct device. This creates a more regular API for tying a char device to its parent without the developer having to set members in the underlying kobject. This patch introduce cdev_device_add and cdev_device_del which replaces a common pattern including setting the kobj parent, calling cdev_add and then calling device_add. It also introduces cdev_set_parent for the few cases that set the kobject parent without using device_add. [1] https://lkml.org/lkml/2017/2/13/700 [2] https://lkml.org/lkml/2017/2/10/370 Signed-off-by: Logan Gunthorpe <logang@deltatee.com> Signed-off-by: Dan Williams <dan.j.williams@intel.com> Reviewed-by: Hans Verkuil <hans.verkuil@cisco.com> Reviewed-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--fs/char_dev.c86
-rw-r--r--include/linux/cdev.h5
2 files changed, 91 insertions, 0 deletions
diff --git a/fs/char_dev.c b/fs/char_dev.c
index 44a240c4bb65..fb8507f521b2 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -471,6 +471,85 @@ int cdev_add(struct cdev *p, dev_t dev, unsigned count)
471 return 0; 471 return 0;
472} 472}
473 473
474/**
475 * cdev_set_parent() - set the parent kobject for a char device
476 * @p: the cdev structure
477 * @kobj: the kobject to take a reference to
478 *
479 * cdev_set_parent() sets a parent kobject which will be referenced
480 * appropriately so the parent is not freed before the cdev. This
481 * should be called before cdev_add.
482 */
483void cdev_set_parent(struct cdev *p, struct kobject *kobj)
484{
485 WARN_ON(!kobj->state_initialized);
486 p->kobj.parent = kobj;
487}
488
489/**
490 * cdev_device_add() - add a char device and it's corresponding
491 * struct device, linkink
492 * @dev: the device structure
493 * @cdev: the cdev structure
494 *
495 * cdev_device_add() adds the char device represented by @cdev to the system,
496 * just as cdev_add does. It then adds @dev to the system using device_add
497 * The dev_t for the char device will be taken from the struct device which
498 * needs to be initialized first. This helper function correctly takes a
499 * reference to the parent device so the parent will not get released until
500 * all references to the cdev are released.
501 *
502 * This helper uses dev->devt for the device number. If it is not set
503 * it will not add the cdev and it will be equivalent to device_add.
504 *
505 * This function should be used whenever the struct cdev and the
506 * struct device are members of the same structure whose lifetime is
507 * managed by the struct device.
508 *
509 * NOTE: Callers must assume that userspace was able to open the cdev and
510 * can call cdev fops callbacks at any time, even if this function fails.
511 */
512int cdev_device_add(struct cdev *cdev, struct device *dev)
513{
514 int rc = 0;
515
516 if (dev->devt) {
517 cdev_set_parent(cdev, &dev->kobj);
518
519 rc = cdev_add(cdev, dev->devt, 1);
520 if (rc)
521 return rc;
522 }
523
524 rc = device_add(dev);
525 if (rc)
526 cdev_del(cdev);
527
528 return rc;
529}
530
531/**
532 * cdev_device_del() - inverse of cdev_device_add
533 * @dev: the device structure
534 * @cdev: the cdev structure
535 *
536 * cdev_device_del() is a helper function to call cdev_del and device_del.
537 * It should be used whenever cdev_device_add is used.
538 *
539 * If dev->devt is not set it will not remove the cdev and will be equivalent
540 * to device_del.
541 *
542 * NOTE: This guarantees that associated sysfs callbacks are not running
543 * or runnable, however any cdevs already open will remain and their fops
544 * will still be callable even after this function returns.
545 */
546void cdev_device_del(struct cdev *cdev, struct device *dev)
547{
548 device_del(dev);
549 if (dev->devt)
550 cdev_del(cdev);
551}
552
474static void cdev_unmap(dev_t dev, unsigned count) 553static void cdev_unmap(dev_t dev, unsigned count)
475{ 554{
476 kobj_unmap(cdev_map, dev, count); 555 kobj_unmap(cdev_map, dev, count);
@@ -482,6 +561,10 @@ static void cdev_unmap(dev_t dev, unsigned count)
482 * 561 *
483 * cdev_del() removes @p from the system, possibly freeing the structure 562 * cdev_del() removes @p from the system, possibly freeing the structure
484 * itself. 563 * itself.
564 *
565 * NOTE: This guarantees that cdev device will no longer be able to be
566 * opened, however any cdevs already open will remain and their fops will
567 * still be callable even after cdev_del returns.
485 */ 568 */
486void cdev_del(struct cdev *p) 569void cdev_del(struct cdev *p)
487{ 570{
@@ -570,5 +653,8 @@ EXPORT_SYMBOL(cdev_init);
570EXPORT_SYMBOL(cdev_alloc); 653EXPORT_SYMBOL(cdev_alloc);
571EXPORT_SYMBOL(cdev_del); 654EXPORT_SYMBOL(cdev_del);
572EXPORT_SYMBOL(cdev_add); 655EXPORT_SYMBOL(cdev_add);
656EXPORT_SYMBOL(cdev_set_parent);
657EXPORT_SYMBOL(cdev_device_add);
658EXPORT_SYMBOL(cdev_device_del);
573EXPORT_SYMBOL(__register_chrdev); 659EXPORT_SYMBOL(__register_chrdev);
574EXPORT_SYMBOL(__unregister_chrdev); 660EXPORT_SYMBOL(__unregister_chrdev);
diff --git a/include/linux/cdev.h b/include/linux/cdev.h
index f8763615a5f2..408bc09ce497 100644
--- a/include/linux/cdev.h
+++ b/include/linux/cdev.h
@@ -4,6 +4,7 @@
4#include <linux/kobject.h> 4#include <linux/kobject.h>
5#include <linux/kdev_t.h> 5#include <linux/kdev_t.h>
6#include <linux/list.h> 6#include <linux/list.h>
7#include <linux/device.h>
7 8
8struct file_operations; 9struct file_operations;
9struct inode; 10struct inode;
@@ -26,6 +27,10 @@ void cdev_put(struct cdev *p);
26 27
27int cdev_add(struct cdev *, dev_t, unsigned); 28int cdev_add(struct cdev *, dev_t, unsigned);
28 29
30void cdev_set_parent(struct cdev *p, struct kobject *kobj);
31int cdev_device_add(struct cdev *cdev, struct device *dev);
32void cdev_device_del(struct cdev *cdev, struct device *dev);
33
29void cdev_del(struct cdev *); 34void cdev_del(struct cdev *);
30 35
31void cd_forget(struct inode *); 36void cd_forget(struct inode *);