[PATCH] drm: Register the debugfs interfaces after loading the driver

Chris Wilson chris at chris-wilson.co.uk
Thu May 26 12:35:18 UTC 2016


In order to give the driver the chance to initialise the data structures
that will be exposed through debugfs, perform driver->load() before
registering the debugfs entries. (Otherwise it may be possible for
userspace to cause an oops through the debugfs interfaces.) As the
driver load is now before debugfs registration, make the registration
non-fatal (as it simply prevents us exposing an optional debug facility
and not hard ABI).

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
 drivers/gpu/drm/drm_debugfs.c | 13 ++++++---
 drivers/gpu/drm/drm_drv.c     | 62 +++++++++++++++++++++++++++++++------------
 2 files changed, 54 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c
index 3bcf8e6a85b3..8f36e014fbd2 100644
--- a/drivers/gpu/drm/drm_debugfs.c
+++ b/drivers/gpu/drm/drm_debugfs.c
@@ -160,10 +160,8 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id,
 	ret = drm_debugfs_create_files(drm_debugfs_list, DRM_DEBUGFS_ENTRIES,
 				       minor->debugfs_root, minor);
 	if (ret) {
-		debugfs_remove(minor->debugfs_root);
-		minor->debugfs_root = NULL;
 		DRM_ERROR("Failed to create core drm debugfs files\n");
-		return ret;
+		goto err_root;
 	}
 
 	if (dev->driver->debugfs_init) {
@@ -171,10 +169,17 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id,
 		if (ret) {
 			DRM_ERROR("DRM: Driver failed to initialize "
 				  "/sys/kernel/debug/dri.\n");
-			return ret;
+			goto err_core;
 		}
 	}
 	return 0;
+
+err_core:
+	drm_debugfs_remove_files(drm_debugfs_list, DRM_DEBUGFS_ENTRIES, minor);
+err_root:
+	debugfs_remove(minor->debugfs_root);
+	minor->debugfs_root = NULL;
+	return ret;
 }
 
 
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index bff89226a344..82d1e80c2bf4 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -307,15 +307,9 @@ static int drm_minor_register(struct drm_device *dev, unsigned int type)
 	if (!minor)
 		return 0;
 
-	ret = drm_debugfs_init(minor, minor->index, drm_debugfs_root);
-	if (ret) {
-		DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n");
-		return ret;
-	}
-
 	ret = device_add(minor->kdev);
 	if (ret)
-		goto err_debugfs;
+		return ret;
 
 	/* replace NULL with @minor so lookups will succeed from now on */
 	spin_lock_irqsave(&drm_minor_lock, flags);
@@ -324,10 +318,36 @@ static int drm_minor_register(struct drm_device *dev, unsigned int type)
 
 	DRM_DEBUG("new minor registered %d\n", minor->index);
 	return 0;
+}
+
+static void drm_debugfs_register(struct drm_device *dev, unsigned int type)
+{
+	struct drm_minor *minor;
+
+	DRM_DEBUG("\n");
+	if (!drm_debugfs_root)
+		return;
+
+	minor = *drm_minor_get_slot(dev, type);
+	if (!minor)
+		return;
+
+	if (drm_debugfs_init(minor, minor->index, drm_debugfs_root))
+		DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n");
+}
+
+static void drm_debugfs_unregister(struct drm_device *dev, unsigned int type)
+{
+	struct drm_minor *minor;
+
+	if (!drm_debugfs_root)
+		return;
+
+	minor = *drm_minor_get_slot(dev, type);
+	if (!minor || !device_is_registered(minor->kdev))
+		return;
 
-err_debugfs:
 	drm_debugfs_cleanup(minor);
-	return ret;
 }
 
 static void drm_minor_unregister(struct drm_device *dev, unsigned int type)
@@ -346,7 +366,6 @@ static void drm_minor_unregister(struct drm_device *dev, unsigned int type)
 
 	device_del(minor->kdev);
 	dev_set_drvdata(minor->kdev, NULL); /* safety belt */
-	drm_debugfs_cleanup(minor);
 }
 
 /**
@@ -460,6 +479,10 @@ EXPORT_SYMBOL(drm_put_dev);
 
 void drm_unplug_dev(struct drm_device *dev)
 {
+	drm_debugfs_unregister(dev, DRM_MINOR_LEGACY);
+	drm_debugfs_unregister(dev, DRM_MINOR_RENDER);
+	drm_debugfs_unregister(dev, DRM_MINOR_CONTROL);
+
 	/* for a USB device */
 	drm_minor_unregister(dev, DRM_MINOR_LEGACY);
 	drm_minor_unregister(dev, DRM_MINOR_RENDER);
@@ -759,6 +782,10 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
 			goto err_minors;
 	}
 
+	drm_debugfs_register(dev, DRM_MINOR_CONTROL);
+	drm_debugfs_register(dev, DRM_MINOR_RENDER);
+	drm_debugfs_register(dev, DRM_MINOR_LEGACY);
+
 	ret = 0;
 	goto out_unlock;
 
@@ -800,6 +827,10 @@ void drm_dev_unregister(struct drm_device *dev)
 	list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head)
 		drm_legacy_rmmap(dev, r_list->map);
 
+	drm_debugfs_unregister(dev, DRM_MINOR_LEGACY);
+	drm_debugfs_unregister(dev, DRM_MINOR_RENDER);
+	drm_debugfs_unregister(dev, DRM_MINOR_CONTROL);
+
 	drm_minor_unregister(dev, DRM_MINOR_LEGACY);
 	drm_minor_unregister(dev, DRM_MINOR_RENDER);
 	drm_minor_unregister(dev, DRM_MINOR_CONTROL);
@@ -904,17 +935,13 @@ static int __init drm_core_init(void)
 	}
 
 	drm_debugfs_root = debugfs_create_dir("dri", NULL);
-	if (!drm_debugfs_root) {
+	if (!drm_debugfs_root)
 		DRM_ERROR("Cannot create /sys/kernel/debug/dri\n");
-		ret = -1;
-		goto err_p3;
-	}
 
 	DRM_INFO("Initialized %s %d.%d.%d %s\n",
 		 CORE_NAME, CORE_MAJOR, CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE);
 	return 0;
-err_p3:
-	drm_sysfs_destroy();
+
 err_p2:
 	unregister_chrdev(DRM_MAJOR, "drm");
 
@@ -925,7 +952,8 @@ err_p1:
 
 static void __exit drm_core_exit(void)
 {
-	debugfs_remove(drm_debugfs_root);
+	if (drm_debugfs_root)
+		debugfs_remove(drm_debugfs_root);
 	drm_sysfs_destroy();
 
 	unregister_chrdev(DRM_MAJOR, "drm");
-- 
2.8.1



More information about the dri-devel mailing list