ttm: make sure userspace can't destroy kernel create memory managers
authorDave Airlie <airlied@redhat.com>
Mon, 18 Feb 2008 00:39:21 +0000 (10:39 +1000)
committerDave Airlie <airlied@redhat.com>
Wed, 20 Feb 2008 01:27:22 +0000 (11:27 +1000)
linux-core/drm_bo.c
linux-core/drm_objects.h
shared-core/i915_init.c
shared-core/nouveau_mem.c
shared-core/radeon_ms_drm.c

index 1f3c2d2..54b8baf 100644 (file)
@@ -2178,7 +2178,7 @@ restart:
        return 0;
 }
 
-int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type)
+int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type, int kern_clean)
 {
        struct drm_buffer_manager *bm = &dev->bm;
        struct drm_mem_type_manager *man = &bm->man[mem_type];
@@ -2194,6 +2194,13 @@ int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type)
                          "memory manager type %u\n", mem_type);
                return ret;
        }
+
+       if ((man->kern_init_type) && (kern_clean == 0)) {
+               DRM_ERROR("Trying to take down kernel initialized "
+                         "memory manager type %u\n", mem_type);
+               return -EPERM;
+       }
+
        man->use_type = 0;
        man->has_type = 0;
 
@@ -2245,9 +2252,9 @@ static int drm_bo_lock_mm(struct drm_device *dev, unsigned mem_type)
        return ret;
 }
 
-int drm_bo_init_mm(struct drm_device *dev,
-                  unsigned type,
-                  unsigned long p_offset, unsigned long p_size)
+int drm_bo_init_mm(struct drm_device *dev, unsigned type,
+                  unsigned long p_offset, unsigned long p_size,
+                  int kern_init)
 {
        struct drm_buffer_manager *bm = &dev->bm;
        int ret = -EINVAL;
@@ -2281,6 +2288,7 @@ int drm_bo_init_mm(struct drm_device *dev,
        }
        man->has_type = 1;
        man->use_type = 1;
+       man->kern_init_type = kern_init;
 
        INIT_LIST_HEAD(&man->lru);
        INIT_LIST_HEAD(&man->pinned);
@@ -2313,7 +2321,7 @@ int drm_bo_driver_finish(struct drm_device *dev)
                man = &bm->man[i];
                if (man->has_type) {
                        man->use_type = 0;
-                       if ((i != DRM_BO_MEM_LOCAL) && drm_bo_clean_mm(dev, i)) {
+                       if ((i != DRM_BO_MEM_LOCAL) && drm_bo_clean_mm(dev, i, 1)) {
                                ret = -EBUSY;
                                DRM_ERROR("DRM memory manager type %d "
                                          "is not clean.\n", i);
@@ -2384,7 +2392,7 @@ int drm_bo_driver_init(struct drm_device *dev)
         * Initialize the system memory buffer type.
         * Other types need to be driver / IOCTL initialized.
         */
-       ret = drm_bo_init_mm(dev, DRM_BO_MEM_LOCAL, 0, 0);
+       ret = drm_bo_init_mm(dev, DRM_BO_MEM_LOCAL, 0, 0, 1);
        if (ret)
                goto out_unlock;
 
@@ -2444,7 +2452,7 @@ int drm_mm_init_ioctl(struct drm_device *dev, void *data, struct drm_file *file_
                goto out;
        }
        ret = drm_bo_init_mm(dev, arg->mem_type,
-                            arg->p_offset, arg->p_size);
+                            arg->p_offset, arg->p_size, 0);
 
 out:
        mutex_unlock(&dev->struct_mutex);
@@ -2483,9 +2491,11 @@ int drm_mm_takedown_ioctl(struct drm_device *dev, void *data, struct drm_file *f
                goto out;
        }
        ret = 0;
-       if (drm_bo_clean_mm(dev, arg->mem_type)) {
-               DRM_ERROR("Memory manager type %d not clean. "
-                         "Delaying takedown\n", arg->mem_type);
+       if (ret = drm_bo_clean_mm(dev, arg->mem_type, 0)) {
+               if (ret == -EINVAL)
+                       DRM_ERROR("Memory manager type %d not clean. "
+                                 "Delaying takedown\n", arg->mem_type);
+               ret = 0;
        }
 out:
        mutex_unlock(&dev->struct_mutex);
index 7b585c3..71da4b2 100644 (file)
@@ -515,6 +515,7 @@ struct drm_buffer_object {
 struct drm_mem_type_manager {
        int has_type;
        int use_type;
+       int kern_init_type;
        struct drm_mm manager;
        struct list_head lru;
        struct list_head pinned;
@@ -681,9 +682,10 @@ extern int drm_bo_mem_space(struct drm_buffer_object *bo,
 extern int drm_bo_move_buffer(struct drm_buffer_object *bo,
                              uint64_t new_mem_flags,
                              int no_wait, int move_unfenced);
-extern int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type);
+extern int drm_bo_clean_mm(struct drm_device *dev, unsigned mem_type, int kern_clean);
 extern int drm_bo_init_mm(struct drm_device *dev, unsigned type,
-                         unsigned long p_offset, unsigned long p_size);
+                         unsigned long p_offset, unsigned long p_size,
+                         int kern_init);
 extern int drm_bo_handle_validate(struct drm_file *file_priv, uint32_t handle,
                                  uint64_t flags, uint64_t mask, uint32_t hint,
                                  uint32_t fence_class, int use_old_fence_class,
index fe2fb38..b2d3f0d 100644 (file)
@@ -167,8 +167,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        i915_probe_agp(dev->pdev, &agp_size, &prealloc_size);
        printk("setting up %ld bytes of VRAM space\n", prealloc_size);
        printk("setting up %ld bytes of TT space\n", (agp_size - prealloc_size));
-       drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, prealloc_size >> PAGE_SHIFT);
-       drm_bo_init_mm(dev, DRM_BO_MEM_TT, prealloc_size >> PAGE_SHIFT, (agp_size - prealloc_size) >> PAGE_SHIFT);
+       drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, prealloc_size >> PAGE_SHIFT, 1);
+       drm_bo_init_mm(dev, DRM_BO_MEM_TT, prealloc_size >> PAGE_SHIFT, (agp_size - prealloc_size) >> PAGE_SHIFT, 1);
 
        I915_WRITE(LP_RING + RING_LEN, 0);
        I915_WRITE(LP_RING + RING_HEAD, 0);
@@ -305,11 +305,11 @@ int i915_driver_unload(struct drm_device *dev)
        mutex_lock(&dev->struct_mutex);
        drm_bo_usage_deref_locked(&dev_priv->ring_buffer);
 
-       if (drm_bo_clean_mm(dev, DRM_BO_MEM_TT)) {
+       if (drm_bo_clean_mm(dev, DRM_BO_MEM_TT, 1)) {
                DRM_ERROR("Memory manager type 3 not clean. "
                          "Delaying takedown\n");
        }
-       if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM)) {
+       if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM, 1)) {
                DRM_ERROR("Memory manager type 3 not clean. "
                          "Delaying takedown\n");
        }
index 3d376ae..80b2990 100644 (file)
@@ -376,7 +376,7 @@ nouveau_mem_init_ttm(struct drm_device *dev)
        bar1_size = drm_get_resource_len(dev, 1) >> PAGE_SHIFT;
        if (bar1_size < vram_size) {
                if ((ret = drm_bo_init_mm(dev, DRM_BO_MEM_PRIV0,
-                                         bar1_size, vram_size - bar1_size))) {
+                                         bar1_size, vram_size - bar1_size, 1))) {
                        DRM_ERROR("Failed PRIV0 mm init: %d\n", ret);
                        return ret;
                }
@@ -387,7 +387,7 @@ nouveau_mem_init_ttm(struct drm_device *dev)
 #ifdef HACK_OLD_MM
        vram_size /= 4;
 #endif
-       if ((ret = drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, vram_size))) {
+       if ((ret = drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, vram_size, 1))) {
                DRM_ERROR("Failed VRAM mm init: %d\n", ret);
                return ret;
        }
@@ -407,7 +407,7 @@ nouveau_mem_init_ttm(struct drm_device *dev)
 
        if ((ret = drm_bo_init_mm(dev, DRM_BO_MEM_TT, 0,
                                  dev_priv->gart_info.aper_size >>
-                                 PAGE_SHIFT))) {
+                                 PAGE_SHIFT, 1))) {
                DRM_ERROR("Failed TT mm init: %d\n", ret);
                return ret;
        }
index bf76b45..857182a 100644 (file)
@@ -160,7 +160,7 @@ int radeon_ms_driver_load(struct drm_device *dev, unsigned long flags)
        dev_priv->fence_reg = SCRATCH_REG2;
        drm_bo_driver_init(dev);
        /* initialize vram */
-       ret = drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, dev_priv->vram.size);
+       ret = drm_bo_init_mm(dev, DRM_BO_MEM_VRAM, 0, dev_priv->vram.size, 1);
        if (ret != 0) {
                radeon_ms_driver_unload(dev);
                return ret;
@@ -176,7 +176,7 @@ int radeon_ms_driver_load(struct drm_device *dev, unsigned long flags)
 
        /* initialize ttm */
        ret = drm_bo_init_mm(dev, DRM_BO_MEM_TT, 0,
-                            dev_priv->gpu_gart_size / RADEON_PAGE_SIZE);
+                            dev_priv->gpu_gart_size / RADEON_PAGE_SIZE, 1);
        if (ret != 0) {
                radeon_ms_driver_unload(dev);
                return ret;
@@ -277,7 +277,7 @@ int radeon_ms_driver_unload(struct drm_device *dev)
        DRM_INFO("[radeon_ms] unloading\n");
        /* clean ttm memory manager */
        mutex_lock(&dev->struct_mutex);
-       if (drm_bo_clean_mm(dev, DRM_BO_MEM_TT)) {
+       if (drm_bo_clean_mm(dev, DRM_BO_MEM_TT, 1)) {
                DRM_ERROR("TT memory manager not clean. Delaying takedown\n");
        }
        mutex_unlock(&dev->struct_mutex);
@@ -289,7 +289,7 @@ int radeon_ms_driver_unload(struct drm_device *dev)
        DRM_INFO("[radeon_ms] bus down\n");
        /* clean vram memory manager */
        mutex_lock(&dev->struct_mutex);
-       if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM)) {
+       if (drm_bo_clean_mm(dev, DRM_BO_MEM_VRAM, 1)) {
                DRM_ERROR("VRAM memory manager not clean. Delaying takedown\n");
        }
        mutex_unlock(&dev->struct_mutex);