drm: track dev_mapping in more robust and flexible way
authorIlija Hadzic <ihadzic@research.bell-labs.com>
Tue, 15 May 2012 20:40:10 +0000 (16:40 -0400)
committerDave Airlie <airlied@redhat.com>
Wed, 25 Jul 2012 04:09:30 +0000 (14:09 +1000)
Setting dev_mapping (pointer to the address_space structure
used for memory mappings) to the address_space of the first
opener's inode and then failing if other openers come in
through a different inode has a few restrictions that are
eliminated by this patch.

If we already have valid dev_mapping and we spot an opener
with different i_node, we force its i_mapping pointer to the
already established address_space structure (first opener's
inode). This will make all mappings from drm device hang off
the same address_space object.

Some benefits (things that now work and didn't work
before) of this patch are:

 * user space can mknod and use any number of device
   nodes and they will all work fine as long as the major
   device number is that of the drm module.
 * user space can even remove the first opener's device
   nodes and mknod the new one and the applications and
   windowing system will still work.
 * GPU drivers can safely assume that dev->dev_mapping is
   correct address_space and just blindly copy it
   into their (private) bdev.dev_mapping

For reference, some discussion that lead to this patch can
be found here:

http://lists.freedesktop.org/archives/dri-devel/2012-April/022283.html

Signed-off-by: Ilija Hadzic <ihadzic@research.bell-labs.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/drm_fops.c
drivers/gpu/drm/nouveau/nouveau_gem.c
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c

index d25a61739a7bb7ccf49db4ecde06551ac4b57e0b..5062eec673f16e9f03024dc2dd8845196a8dd0ef 100644 (file)
@@ -140,12 +140,12 @@ int drm_open(struct inode *inode, struct file *filp)
        }
        if (!retcode) {
                mutex_lock(&dev->struct_mutex);
-               if (minor->type == DRM_MINOR_LEGACY) {
-                       if (dev->dev_mapping == NULL)
-                               dev->dev_mapping = inode->i_mapping;
-                       else if (dev->dev_mapping != inode->i_mapping)
-                               retcode = -ENODEV;
-               }
+               if (dev->dev_mapping == NULL)
+                       dev->dev_mapping = &inode->i_data;
+               /* ihold ensures nobody can remove inode with our i_data */
+               ihold(container_of(dev->dev_mapping, struct inode, i_data));
+               inode->i_mapping = dev->dev_mapping;
+               filp->f_mapping = dev->dev_mapping;
                mutex_unlock(&dev->struct_mutex);
        }
 
@@ -509,6 +509,9 @@ int drm_release(struct inode *inode, struct file *filp)
                }
        }
 
+       BUG_ON(dev->dev_mapping == NULL);
+       iput(container_of(dev->dev_mapping, struct inode, i_data));
+
        /* drop the reference held my the file priv */
        drm_master_put(&file_priv->master);
        file_priv->is_master = 0;
index 30f5423169444ec841d9af44f0d816cb3547ae17..fe3f5a821b8483bcf44b0b0017e92eca97290451 100644 (file)
@@ -207,8 +207,7 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data,
        struct nouveau_bo *nvbo = NULL;
        int ret = 0;
 
-       if (unlikely(dev_priv->ttm.bdev.dev_mapping == NULL))
-               dev_priv->ttm.bdev.dev_mapping = dev_priv->dev->dev_mapping;
+       dev_priv->ttm.bdev.dev_mapping = dev->dev_mapping;
 
        if (!dev_priv->engine.vram.flags_valid(dev, req->info.tile_flags)) {
                NV_ERROR(dev, "bad page flags: 0x%08x\n", req->info.tile_flags);
index 6ecb2006e27eb0ac325bc173d76b075d150268b6..1f77a5afc011b9c5b998ae3ee544aaeed2386202 100644 (file)
@@ -115,9 +115,7 @@ int radeon_bo_create(struct radeon_device *rdev,
 
        size = ALIGN(size, PAGE_SIZE);
 
-       if (unlikely(rdev->mman.bdev.dev_mapping == NULL)) {
-               rdev->mman.bdev.dev_mapping = rdev->ddev->dev_mapping;
-       }
+       rdev->mman.bdev.dev_mapping = rdev->ddev->dev_mapping;
        if (kernel) {
                type = ttm_bo_type_kernel;
        } else if (sg) {
index 0881131a03888f699403fb9ccc7b2d64f7232df6..5b71c716d83f1845d9672b5c1cd5bd9bdb5022ba 100644 (file)
@@ -734,9 +734,7 @@ int radeon_ttm_init(struct radeon_device *rdev)
        }
        DRM_INFO("radeon: %uM of GTT memory ready.\n",
                 (unsigned)(rdev->mc.gtt_size / (1024 * 1024)));
-       if (unlikely(rdev->mman.bdev.dev_mapping == NULL)) {
-               rdev->mman.bdev.dev_mapping = rdev->ddev->dev_mapping;
-       }
+       rdev->mman.bdev.dev_mapping = rdev->ddev->dev_mapping;
 
        r = radeon_ttm_debugfs_init(rdev);
        if (r) {
index 5d5632f5265b7cdbe57e2410ce046bf342ad7d19..4d9edead01acdbcb900a3fdca87d5ed08cdab682 100644 (file)
@@ -769,10 +769,7 @@ static int vmw_driver_open(struct drm_device *dev, struct drm_file *file_priv)
                goto out_no_tfile;
 
        file_priv->driver_priv = vmw_fp;
-
-       if (unlikely(dev_priv->bdev.dev_mapping == NULL))
-               dev_priv->bdev.dev_mapping =
-                       file_priv->filp->f_path.dentry->d_inode->i_mapping;
+       dev_priv->bdev.dev_mapping = dev->dev_mapping;
 
        return 0;