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

Reply via email to