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

char_dev: pin parent kobject

In certain cases (for example when a cdev structure is embedded into
another object whose lifetime is controlled by a separate kobject) it is
beneficial to tie lifetime of another object to the lifetime of
character device so that related object is not freed until after
char_dev object is freed.

To achieve this let's pin kobject's parent when doing cdev_add() and
unpin when last reference to cdev structure is being released.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Acked-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Dmitry Torokhov and committed by
Linus Torvalds
2f0157f1 6f0c0580

+17 -1
+17 -1
fs/char_dev.c
··· 471 471 */ 472 472 int cdev_add(struct cdev *p, dev_t dev, unsigned count) 473 473 { 474 + int error; 475 + 474 476 p->dev = dev; 475 477 p->count = count; 476 - return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p); 478 + 479 + error = kobj_map(cdev_map, dev, count, NULL, 480 + exact_match, exact_lock, p); 481 + if (error) 482 + return error; 483 + 484 + kobject_get(p->kobj.parent); 485 + 486 + return 0; 477 487 } 478 488 479 489 static void cdev_unmap(dev_t dev, unsigned count) ··· 508 498 static void cdev_default_release(struct kobject *kobj) 509 499 { 510 500 struct cdev *p = container_of(kobj, struct cdev, kobj); 501 + struct kobject *parent = kobj->parent; 502 + 511 503 cdev_purge(p); 504 + kobject_put(parent); 512 505 } 513 506 514 507 static void cdev_dynamic_release(struct kobject *kobj) 515 508 { 516 509 struct cdev *p = container_of(kobj, struct cdev, kobj); 510 + struct kobject *parent = kobj->parent; 511 + 517 512 cdev_purge(p); 518 513 kfree(p); 514 + kobject_put(parent); 519 515 } 520 516 521 517 static struct kobj_type ktype_cdev_default = {