drm: Move master pointer from drm_minor to drm_device
authorDaniel Vetter <daniel.vetter@ffwll.ch>
Tue, 21 Jun 2016 08:54:12 +0000 (10:54 +0200)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Tue, 21 Jun 2016 19:43:24 +0000 (21:43 +0200)
There can only be one current master, and it's for the overall device.
Render/control minors don't support master-based auth at all.

This simplifies the master logic a lot, at least in my eyes: All these
additional pointer chases are just confusing.

While doing the conversion I spotted some locking fail:
- drm_lock/drm_auth check dev->master without holding the
  master_mutex. This is fallout from

  commit c996fd0b956450563454e7ccc97a82ca31f9d043
  Author: Thomas Hellstrom <thellstrom@vmware.com>
  Date:   Tue Feb 25 19:57:44 2014 +0100

      drm: Protect the master management with a drm_device::master_mutex v3

  but I honestly don't care one bit about those old legacy drivers
  using this.

- debugfs name info should just grab master_mutex.

- And the fbdev helper looked at it to figure out whether someone is
  using KMS. We just need a consistent value, so READ_ONCE. Aside: We
  should probably check if anyone has opened a control node too, but I
  guess current userspace doesn't really do that yet.

v2: Balance locking, reported by Julia.

v3: Rebase on top of Chris' oops fixes.

Cc: Julia Lawall <julia.lawall@lip6.fr>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> (v2)
Reviewed-by: Emil Velikov <emil.l.velikov@gmail.com> (v2)
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1466499262-18717-1-git-send-email-daniel.vetter@ffwll.ch
drivers/gpu/drm/drm_auth.c
drivers/gpu/drm/drm_bufs.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_info.c
drivers/gpu/drm/drm_lock.c
drivers/gpu/drm/sis/sis_mm.c
drivers/gpu/drm/via/via_mm.c
include/drm/drmP.h

index d858e69..6bba6b9 100644 (file)
@@ -128,13 +128,13 @@ static int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv)
        lockdep_assert_held_once(&dev->master_mutex);
 
        /* create a new master */
-       fpriv->minor->master = drm_master_create(fpriv->minor->dev);
-       if (!fpriv->minor->master)
+       dev->master = drm_master_create(dev);
+       if (!dev->master)
                return -ENOMEM;
 
        /* take another reference for the copy in the local file priv */
        old_master = fpriv->master;
-       fpriv->master = drm_master_get(fpriv->minor->master);
+       fpriv->master = drm_master_get(dev->master);
 
        if (dev->driver->master_create) {
                ret = dev->driver->master_create(dev, fpriv->master);
@@ -157,7 +157,7 @@ static int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv)
 
 out_err:
        /* drop both references and restore old master on failure */
-       drm_master_put(&fpriv->minor->master);
+       drm_master_put(&dev->master);
        drm_master_put(&fpriv->master);
        fpriv->master = old_master;
 
@@ -173,7 +173,7 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data,
        if (file_priv->is_master)
                goto out_unlock;
 
-       if (file_priv->minor->master) {
+       if (dev->master) {
                ret = -EINVAL;
                goto out_unlock;
        }
@@ -188,13 +188,13 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data,
                goto out_unlock;
        }
 
-       file_priv->minor->master = drm_master_get(file_priv->master);
+       dev->master = drm_master_get(file_priv->master);
        file_priv->is_master = 1;
        if (dev->driver->master_set) {
                ret = dev->driver->master_set(dev, file_priv, false);
                if (unlikely(ret != 0)) {
                        file_priv->is_master = 0;
-                       drm_master_put(&file_priv->minor->master);
+                       drm_master_put(&dev->master);
                }
        }
 
@@ -212,13 +212,13 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
        if (!file_priv->is_master)
                goto out_unlock;
 
-       if (!file_priv->minor->master)
+       if (!dev->master)
                goto out_unlock;
 
        ret = 0;
        if (dev->driver->master_drop)
                dev->driver->master_drop(dev, file_priv, false);
-       drm_master_put(&file_priv->minor->master);
+       drm_master_put(&dev->master);
        file_priv->is_master = 0;
 
 out_unlock:
@@ -234,10 +234,10 @@ int drm_master_open(struct drm_file *file_priv)
        /* if there is no current master make this fd it, but do not create
         * any master object for render clients */
        mutex_lock(&dev->master_mutex);
-       if (!file_priv->minor->master)
+       if (!dev->master)
                ret = drm_new_set_master(dev, file_priv);
        else
-               file_priv->master = drm_master_get(file_priv->minor->master);
+               file_priv->master = drm_master_get(dev->master);
        mutex_unlock(&dev->master_mutex);
 
        return ret;
@@ -271,11 +271,11 @@ void drm_master_release(struct drm_file *file_priv)
                mutex_unlock(&dev->struct_mutex);
        }
 
-       if (file_priv->minor->master == file_priv->master) {
+       if (dev->master == file_priv->master) {
                /* drop the reference held my the minor */
                if (dev->driver->master_drop)
                        dev->driver->master_drop(dev, file_priv, true);
-               drm_master_put(&file_priv->minor->master);
+               drm_master_put(&dev->master);
        }
 out:
        /* drop the master reference held by the file priv */
index 9b34158..c3a12cd 100644 (file)
@@ -51,7 +51,7 @@ static struct drm_map_list *drm_find_matching_map(struct drm_device *dev,
                 */
                if (!entry->map ||
                    map->type != entry->map->type ||
-                   entry->master != dev->primary->master)
+                   entry->master != dev->master)
                        continue;
                switch (map->type) {
                case _DRM_SHM:
@@ -245,12 +245,12 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
                map->offset = (unsigned long)map->handle;
                if (map->flags & _DRM_CONTAINS_LOCK) {
                        /* Prevent a 2nd X Server from creating a 2nd lock */
-                       if (dev->primary->master->lock.hw_lock != NULL) {
+                       if (dev->master->lock.hw_lock != NULL) {
                                vfree(map->handle);
                                kfree(map);
                                return -EBUSY;
                        }
-                       dev->sigdata.lock = dev->primary->master->lock.hw_lock = map->handle;   /* Pointer to lock */
+                       dev->sigdata.lock = dev->master->lock.hw_lock = map->handle;    /* Pointer to lock */
                }
                break;
        case _DRM_AGP: {
@@ -356,7 +356,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
        mutex_unlock(&dev->struct_mutex);
 
        if (!(map->flags & _DRM_DRIVER))
-               list->master = dev->primary->master;
+               list->master = dev->master;
        *maplist = list;
        return 0;
 }
index 0bac524..0a06f91 100644 (file)
@@ -464,7 +464,7 @@ static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
 
        /* Sometimes user space wants everything disabled, so don't steal the
         * display if there's a master. */
-       if (dev->primary->master)
+       if (READ_ONCE(dev->master))
                return false;
 
        drm_for_each_crtc(crtc, dev) {
index e2d2543..d6cfd53 100644 (file)
@@ -50,7 +50,12 @@ int drm_name_info(struct seq_file *m, void *data)
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_minor *minor = node->minor;
        struct drm_device *dev = minor->dev;
-       struct drm_master *master = minor->master;
+       struct drm_master *master;
+
+       mutex_lock(&dev->master_mutex);
+       master = dev->master;
+       if (!master)
+               goto out_unlock;
 
        seq_printf(m, "%s", dev->driver->name);
        if (dev->dev)
@@ -60,6 +65,8 @@ int drm_name_info(struct seq_file *m, void *data)
        if (dev->unique)
                seq_printf(m, " unique=%s", dev->unique);
        seq_printf(m, "\n");
+out_unlock:
+       mutex_unlock(&dev->master_mutex);
 
        return 0;
 }
index 0fb8f9e..ae0a4d3 100644 (file)
@@ -334,7 +334,7 @@ void drm_legacy_lock_release(struct drm_device *dev, struct file *filp)
        struct drm_file *file_priv = filp->private_data;
 
        /* if the master has gone away we can't do anything with the lock */
-       if (!file_priv->minor->master)
+       if (!dev->master)
                return;
 
        if (drm_legacy_i_have_hw_lock(dev, file_priv)) {
index 93ad8a5..03defda 100644 (file)
@@ -316,7 +316,7 @@ void sis_reclaim_buffers_locked(struct drm_device *dev,
        struct sis_file_private *file_priv = file->driver_priv;
        struct sis_memblock *entry, *next;
 
-       if (!(file->minor->master && file->master->lock.hw_lock))
+       if (!(dev->master && file->master->lock.hw_lock))
                return;
 
        drm_legacy_idlelock_take(&file->master->lock);
index 4f20742..a04ef1c 100644 (file)
@@ -208,7 +208,7 @@ void via_reclaim_buffers_locked(struct drm_device *dev,
        struct via_file_private *file_priv = file->driver_priv;
        struct via_memblock *entry, *next;
 
-       if (!(file->minor->master && file->master->lock.hw_lock))
+       if (!(dev->master && file->master->lock.hw_lock))
                return;
 
        drm_legacy_idlelock_take(&file->master->lock);
index 084fd14..3d9a782 100644 (file)
@@ -336,7 +336,7 @@ struct drm_file {
        void *driver_priv;
 
        struct drm_master *master; /* master this node is currently associated with
-                                     N.B. not always minor->master */
+                                     N.B. not always dev->master */
        /**
         * fbs - List of framebuffers associated with this file.
         *
@@ -708,9 +708,6 @@ struct drm_minor {
 
        struct list_head debugfs_list;
        struct mutex debugfs_lock; /* Protects debugfs_list. */
-
-       /* currently active master for this node. Protected by master_mutex */
-       struct drm_master *master;
 };
 
 
@@ -759,6 +756,10 @@ struct drm_device {
        struct drm_minor *control;              /**< Control node */
        struct drm_minor *primary;              /**< Primary node */
        struct drm_minor *render;               /**< Render node */
+
+       /* currently active master for this device. Protected by master_mutex */
+       struct drm_master *master;
+
        atomic_t unplugged;                     /**< Flag whether dev is dead */
        struct inode *anon_inode;               /**< inode for private address-space */
        char *unique;                           /**< unique name of the device */