diff mbox

drm: Register the debugfs interfaces after loading the driver

Message ID 1464266118-18567-1-git-send-email-chris@chris-wilson.co.uk (mailing list archive)
State New, archived
Headers show

Commit Message

Chris Wilson May 26, 2016, 12:35 p.m. UTC
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@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(-)

Comments

Chris Wilson May 26, 2016, 1:06 p.m. UTC | #1
On Thu, May 26, 2016 at 01:35:18PM +0100, Chris Wilson wrote:
> 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).

The alternative here would be for i915.ko to stop registering a
driver->debugfs_init and do it as part of its registration phase (like
sysfs).
-Chris
Daniel Vetter May 27, 2016, 6:47 a.m. UTC | #2
On Thu, May 26, 2016 at 02:06:13PM +0100, Chris Wilson wrote:
> On Thu, May 26, 2016 at 01:35:18PM +0100, Chris Wilson wrote:
> > 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).
> 
> The alternative here would be for i915.ko to stop registering a
> driver->debugfs_init and do it as part of its registration phase (like
> sysfs).

I think the right fix would be to demidlayer i915 and stop using the
->load callback. Then we do have the right ordering, since debugfs setup
is done as part of the register phase.

It's just that for historical raisins load is called after the devnodes
are registered (because some dri1 drivers want to look at master/sarea
stuff iirc).
-Daniel
Chris Wilson May 27, 2016, 7:44 a.m. UTC | #3
On Fri, May 27, 2016 at 08:47:48AM +0200, Daniel Vetter wrote:
> On Thu, May 26, 2016 at 02:06:13PM +0100, Chris Wilson wrote:
> > On Thu, May 26, 2016 at 01:35:18PM +0100, Chris Wilson wrote:
> > > 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).
> > 
> > The alternative here would be for i915.ko to stop registering a
> > driver->debugfs_init and do it as part of its registration phase (like
> > sysfs).
> 
> I think the right fix would be to demidlayer i915 and stop using the
> ->load callback. Then we do have the right ordering, since debugfs setup
> is done as part of the register phase.

We would need to take control from drm_get_pci_dev() if we want to
publish the device nodes during our registration phase (which we do).
One way would be to opencode drm_get_pci_dev() and do the driver setup
entirely ourselves from i915_pci_probe() then register.

Seems reasonable, biggest challenge will be to make sure we aren't
dependent on the minors before registration (but that shouldn't be too
much of a challenge, at worst it means we have bad ordering to fixup).
-Chris
diff mbox

Patch

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");