linuxkpi: avoid counting per-thread use for the embedded linux cdevs

The counter is not used to control destroy.

Reviewed by:	hselasky
Sponsored by:	Mellanox Technologies/NVidia Networking
MFC after:	1 week
This commit is contained in:
Konstantin Belousov 2021-03-30 11:45:24 +03:00
parent 7f9867f8c6
commit f6b108837e
2 changed files with 30 additions and 14 deletions

View file

@ -717,15 +717,19 @@ linux_get_fop(struct linux_file *filp, const struct file_operations **fop,
ldev = filp->f_cdev;
*fop = filp->f_op;
if (ldev != NULL) {
for (siref = ldev->siref;;) {
if ((siref & LDEV_SI_DTR) != 0) {
ldev = &dummy_ldev;
siref = ldev->siref;
*fop = ldev->ops;
MPASS((ldev->siref & LDEV_SI_DTR) == 0);
} else if (atomic_fcmpset_int(&ldev->siref, &siref,
siref + LDEV_SI_REF)) {
break;
if (ldev->kobj.ktype == &linux_cdev_static_ktype) {
refcount_acquire(&ldev->refs);
} else {
for (siref = ldev->siref;;) {
if ((siref & LDEV_SI_DTR) != 0) {
ldev = &dummy_ldev;
*fop = ldev->ops;
siref = ldev->siref;
MPASS((ldev->siref & LDEV_SI_DTR) == 0);
} else if (atomic_fcmpset_int(&ldev->siref,
&siref, siref + LDEV_SI_REF)) {
break;
}
}
}
}
@ -738,8 +742,13 @@ linux_drop_fop(struct linux_cdev *ldev)
if (ldev == NULL)
return;
MPASS((ldev->siref & ~LDEV_SI_DTR) != 0);
atomic_subtract_int(&ldev->siref, LDEV_SI_REF);
if (ldev->kobj.ktype == &linux_cdev_static_ktype) {
linux_cdev_deref(ldev);
} else {
MPASS(ldev->kobj.ktype == &linux_cdev_ktype);
MPASS((ldev->siref & ~LDEV_SI_DTR) != 0);
atomic_subtract_int(&ldev->siref, LDEV_SI_REF);
}
}
#define OPW(fp,td,code) ({ \

View file

@ -2199,8 +2199,8 @@ linux_completion_done(struct completion *c)
static void
linux_cdev_deref(struct linux_cdev *ldev)
{
if (refcount_release(&ldev->refs))
if (refcount_release(&ldev->refs) &&
ldev->kobj.ktype == &linux_cdev_ktype)
kfree(ldev);
}
@ -2220,12 +2220,17 @@ linux_cdev_release(struct kobject *kobj)
static void
linux_cdev_static_release(struct kobject *kobj)
{
struct cdev *cdev;
struct linux_cdev *ldev;
struct kobject *parent;
ldev = container_of(kobj, struct linux_cdev, kobj);
parent = kobj->parent;
linux_destroy_dev(ldev);
cdev = ldev->cdev;
if (cdev != NULL) {
destroy_dev(cdev);
ldev->cdev = NULL;
}
kobject_put(parent);
}
@ -2237,6 +2242,8 @@ linux_destroy_dev(struct linux_cdev *ldev)
return;
MPASS((ldev->siref & LDEV_SI_DTR) == 0);
MPASS(ldev->kobj.ktype == &linux_cdev_ktype);
atomic_set_int(&ldev->siref, LDEV_SI_DTR);
while ((atomic_load_int(&ldev->siref) & ~LDEV_SI_DTR) != 0)
pause("ldevdtr", hz / 4);