summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_file.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2020-01-24 13:56:26 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2020-01-24 18:41:34 +0100
commit7a2c65dd32b1cfa8bae55250dfdfe3d049e2f336 (patch)
tree0e99dbcc57f63cf27809945e3efd0d12af08112f /drivers/gpu/drm/drm_file.c
parentdt-bindings: restrict properties for sitronix,st7735r (diff)
downloadlinux-7a2c65dd32b1cfa8bae55250dfdfe3d049e2f336.tar.xz
linux-7a2c65dd32b1cfa8bae55250dfdfe3d049e2f336.zip
drm: Release filp before global lock
The file is not part of the global drm resource and can be released prior to take the global mutex to drop the open_count (and potentially close) the drm device. As the global mutex is indeed global, not only within the device but across devices, a slow file release mechanism can bottleneck the entire system. However, inside drm_close_helper() there are a number of dev->driver callbacks that take the drm_device as the first parameter... Worryingly some of those callbacks may be (implicitly) depending on the global mutex. v2: Drop the debug message for the open-count, it's included with the drm_file_free() debug message -- and for good measure make that up as reading outside of the mutex. v3: Separate the calling of the filp cleanup outside of drm_global_mutex into a new drm_release_noglobal() hook, so that we can phase the transition. drm/savage relies on the global mutex, and there may be more, so be cautious. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Thomas Hellström (VMware) <thomas_os@shipmail.org> Reviewed-by: Thomas Hellström (VMware) <thomas_os@shipmail.org> Link: https://patchwork.freedesktop.org/patch/msgid/20200124125627.125042-1-chris@chris-wilson.co.uk
Diffstat (limited to 'drivers/gpu/drm/drm_file.c')
-rw-r--r--drivers/gpu/drm/drm_file.c36
1 files changed, 35 insertions, 1 deletions
diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c
index 92d16724f949..e25306c49cc6 100644
--- a/drivers/gpu/drm/drm_file.c
+++ b/drivers/gpu/drm/drm_file.c
@@ -220,7 +220,7 @@ void drm_file_free(struct drm_file *file)
DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
task_pid_nr(current),
(long)old_encode_dev(file->minor->kdev->devt),
- dev->open_count);
+ READ_ONCE(dev->open_count));
if (drm_core_check_feature(dev, DRIVER_LEGACY) &&
dev->driver->preclose)
@@ -456,6 +456,40 @@ int drm_release(struct inode *inode, struct file *filp)
EXPORT_SYMBOL(drm_release);
/**
+ * drm_release_noglobal - release method for DRM file
+ * @inode: device inode
+ * @filp: file pointer.
+ *
+ * This function may be used by drivers as their &file_operations.release
+ * method. It frees any resources associated with the open file prior to taking
+ * the drm_global_mutex, which then calls the &drm_driver.postclose driver
+ * callback. If this is the last open file for the DRM device also proceeds to
+ * call the &drm_driver.lastclose driver callback.
+ *
+ * RETURNS:
+ *
+ * Always succeeds and returns 0.
+ */
+int drm_release_noglobal(struct inode *inode, struct file *filp)
+{
+ struct drm_file *file_priv = filp->private_data;
+ struct drm_minor *minor = file_priv->minor;
+ struct drm_device *dev = minor->dev;
+
+ drm_close_helper(filp);
+
+ mutex_lock(&drm_global_mutex);
+ if (!--dev->open_count)
+ drm_lastclose(dev);
+ mutex_unlock(&drm_global_mutex);
+
+ drm_minor_release(minor);
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_release_noglobal);
+
+/**
* drm_read - read method for DRM file
* @filp: file pointer
* @buffer: userspace destination pointer for the read