[PATCH] drm: take global drm mutex around sysfs files

Jesse Barnes jbarnes at virtuousgeek.org
Thu Feb 9 09:56:39 PST 2012


This prevents a race between module init and sysfs access (usually only
seen at module reload time, or if somehow your userspace starts fast
enough and pokes at /sys/class/drm while the drivers are still
initializing).

Signed-off-by: Jesse Barnes <jbarnes at virtuousgeek.org>
---
 drivers/gpu/drm/drm_sysfs.c |   75 ++++++++++++++++++++++++++++++------------
 1 files changed, 53 insertions(+), 22 deletions(-)

diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
index 0f9ef9b..bb8bbc3 100644
--- a/drivers/gpu/drm/drm_sysfs.c
+++ b/drivers/gpu/drm/drm_sysfs.c
@@ -161,15 +161,20 @@ static ssize_t status_show(struct device *device,
 	enum drm_connector_status status;
 	int ret;
 
+	mutex_lock(&drm_global_mutex);
+
 	ret = mutex_lock_interruptible(&connector->dev->mode_config.mutex);
 	if (ret)
-		return ret;
+		goto out;
 
 	status = connector->funcs->detect(connector, true);
 	mutex_unlock(&connector->dev->mode_config.mutex);
 
-	return snprintf(buf, PAGE_SIZE, "%s\n",
-			drm_get_connector_status_name(status));
+	ret = snprintf(buf, PAGE_SIZE, "%s\n",
+		       drm_get_connector_status_name(status));
+out:
+	mutex_unlock(&drm_global_mutex);
+	return ret;
 }
 
 static ssize_t dpms_show(struct device *device,
@@ -181,14 +186,20 @@ static ssize_t dpms_show(struct device *device,
 	uint64_t dpms_status;
 	int ret;
 
+	mutex_lock(&drm_global_mutex);
 	ret = drm_connector_property_get_value(connector,
 					    dev->mode_config.dpms_property,
 					    &dpms_status);
-	if (ret)
-		return 0;
+	if (ret) {
+		ret = 0;
+		goto out;
+	}
 
-	return snprintf(buf, PAGE_SIZE, "%s\n",
+	ret = snprintf(buf, PAGE_SIZE, "%s\n",
 			drm_get_dpms_name((int)dpms_status));
+out:
+	mutex_unlock(&drm_global_mutex);
+	return ret;
 }
 
 static ssize_t enabled_show(struct device *device,
@@ -196,9 +207,13 @@ static ssize_t enabled_show(struct device *device,
 			   char *buf)
 {
 	struct drm_connector *connector = to_drm_connector(device);
+	int ret;
 
-	return snprintf(buf, PAGE_SIZE, "%s\n", connector->encoder ? "enabled" :
-			"disabled");
+	mutex_lock(&drm_global_mutex);
+	ret = snprintf(buf, PAGE_SIZE, "%s\n", connector->encoder ? "enabled" :
+		       "disabled");
+	mutex_unlock(&drm_global_mutex);
+	return ret;
 }
 
 static ssize_t edid_show(struct file *filp, struct kobject *kobj,
@@ -210,21 +225,30 @@ static ssize_t edid_show(struct file *filp, struct kobject *kobj,
 	unsigned char *edid;
 	size_t size;
 
-	if (!connector->edid_blob_ptr)
-		return 0;
+	mutex_lock(&drm_global_mutex);
+	if (!connector->edid_blob_ptr) {
+		count = 0;
+		goto out;
+	}
 
 	edid = connector->edid_blob_ptr->data;
 	size = connector->edid_blob_ptr->length;
-	if (!edid)
-		return 0;
+	if (!edid) {
+		count = 0;
+		goto out;
+	}
 
-	if (off >= size)
-		return 0;
+	if (off >= size) {
+		count = 0;
+		goto out;
+	}
 
 	if (off + count > size)
 		count = size - off;
 	memcpy(buf, edid + off, count);
 
+out:
+	mutex_unlock(&drm_global_mutex);
 	return count;
 }
 
@@ -236,11 +260,12 @@ static ssize_t modes_show(struct device *device,
 	struct drm_display_mode *mode;
 	int written = 0;
 
+	mutex_lock(&drm_global_mutex);
 	list_for_each_entry(mode, &connector->modes, head) {
 		written += snprintf(buf + written, PAGE_SIZE - written, "%s\n",
 				    mode->name);
 	}
-
+	mutex_unlock(&drm_global_mutex);
 	return written;
 }
 
@@ -253,7 +278,9 @@ static ssize_t subconnector_show(struct device *device,
 	struct drm_property *prop = NULL;
 	uint64_t subconnector;
 	int is_tv = 0;
-	int ret;
+	int ret = 0;
+
+	mutex_lock(&drm_global_mutex);
 
 	switch (connector->connector_type) {
 		case DRM_MODE_CONNECTOR_DVII:
@@ -268,21 +295,25 @@ static ssize_t subconnector_show(struct device *device,
 			break;
 		default:
 			DRM_ERROR("Wrong connector type for this property\n");
-			return 0;
+			goto out;
 	}
 
 	if (!prop) {
 		DRM_ERROR("Unable to find subconnector property\n");
-		return 0;
+		goto out;
 	}
 
 	ret = drm_connector_property_get_value(connector, prop, &subconnector);
 	if (ret)
-		return 0;
+		goto out;
 
-	return snprintf(buf, PAGE_SIZE, "%s", is_tv ?
-			drm_get_tv_subconnector_name((int)subconnector) :
-			drm_get_dvi_i_subconnector_name((int)subconnector));
+	ret = snprintf(buf, PAGE_SIZE, "%s", is_tv ?
+		       drm_get_tv_subconnector_name((int)subconnector) :
+		       drm_get_dvi_i_subconnector_name((int)subconnector));
+
+out:
+	mutex_unlock(&drm_global_mutex);
+	return ret;
 }
 
 static ssize_t select_subconnector_show(struct device *device,
-- 
1.7.5.4



More information about the dri-devel mailing list