--- a/sys/dev/drm/drm_drv.c +++ b/sys/dev/drm/drm_drv.c @@ -26,6 +26,8 @@ * DEALINGS IN THE SOFTWARE. */ +#include /* destroy_dev() for drm_minor_free() */ + #include #include #include @@ -183,9 +185,18 @@ if (!minor) return; -#if 0 - put_device(minor->kdev); -#endif +/* + * DF-4378: on DragonFly drm_sysfs_minor_alloc() kzalloc()s the + * struct device and make_dev()s the "dri/cardN" cdev. Release both + * here or every driver attach/detach cycle leaks them and leaves a + * stale /dev/dri node with si_drv1 dangling at the freed drm_device. + */ + if (minor->devnode != NULL) { + destroy_dev(minor->devnode); + minor->devnode = NULL; + } + if (minor->kdev != NULL) + kfree(minor->kdev); spin_lock_irqsave(&drm_minor_lock, flags); idr_remove(&drm_minors_idr, minor->index); --- a/sys/dev/drm/include/drm/drm_file.h +++ b/sys/dev/drm/include/drm/drm_file.h @@ -78,6 +78,7 @@ int index; /* Minor device number */ int type; /* Control or render */ struct device *kdev; /* Linux device */ + struct cdev *devnode; /* DF: devfs cdev from make_dev() */ struct drm_device *dev; struct dentry *debugfs_root; --- a/sys/dev/drm/drm_sysfs.c +++ b/sys/dev/drm/drm_sysfs.c @@ -97,6 +97,8 @@ devnode = make_dev(&drm_cdevsw, minor->index, DRM_DEV_UID, DRM_DEV_GID, DRM_DEV_MODE, "dri/%s", dev_str); + minor->devnode = devnode; /* DF-4378: so drm_minor_free can destroy it */ + kdev->parent = minor->dev->dev; dev_set_drvdata(kdev, minor);