Restore pre-idr semantics for drawable information.
authorMichel Dänzer <michel@tungstengraphics.com>
Tue, 3 Jul 2007 09:41:44 +0000 (11:41 +0200)
committerMichel Dänzer <michel@tungstengraphics.com>
Tue, 3 Jul 2007 09:41:44 +0000 (11:41 +0200)
There's a difference between a drawable ID not having valid drawable
information and not being allocated at all. Not making the distinction would
break i915 DRM swap scheduling with older X servers that don't push drawable
cliprect information to the DRM.

linux-core/drm_drawable.c

index 74f0bb5..7657e95 100644 (file)
@@ -37,6 +37,8 @@
 
 #include "drmP.h"
 
+#define NO_DRW_INFO (void*)1
+
 /**
  * Allocate drawable ID and memory to store information about it.
  */
@@ -44,24 +46,18 @@ int drm_adddraw(DRM_IOCTL_ARGS)
 {
        DRM_DEVICE;
        unsigned long irqflags;
-       struct drm_drawable_info *draw_info;
        drm_draw_t draw;
        int new_id = 0;
        int ret;
 
-       draw_info = drm_calloc(1, sizeof(*draw_info), DRM_MEM_BUFS);
-       if (!draw_info)
-               return -ENOMEM;
-
 again:
        if (idr_pre_get(&dev->drw_idr, GFP_KERNEL) == 0) {
                DRM_ERROR("Out of memory expanding drawable idr\n");
-               drm_free(draw_info, sizeof(struct drm_drawable_info), DRM_MEM_BUFS);
                return -ENOMEM;
        }
 
        spin_lock_irqsave(&dev->drw_lock, irqflags);
-       ret = idr_get_new_above(&dev->drw_idr, draw_info, 1, &new_id);
+       ret = idr_get_new_above(&dev->drw_idr, NO_DRW_INFO, 1, &new_id);
        if (ret == -EAGAIN) {
                spin_unlock_irqrestore(&dev->drw_lock, irqflags);
                goto again;
@@ -86,21 +82,16 @@ int drm_rmdraw(DRM_IOCTL_ARGS)
        DRM_DEVICE;
        drm_draw_t draw;
        unsigned long irqflags;
-       struct drm_drawable_info *draw_info;
 
        DRM_COPY_FROM_USER_IOCTL(draw, (drm_draw_t __user *) data,
                                 sizeof(draw));
 
-       draw_info = idr_find(&dev->drw_idr, draw.handle);
-       if (!draw_info) {
-               DRM_DEBUG("No such drawable %d\n", draw.handle);
-               return -EINVAL;
-       }
-
        spin_lock_irqsave(&dev->drw_lock, irqflags);
 
+       drm_free(drm_get_drawable_info(dev, draw.handle),
+                sizeof(struct drm_drawable_info), DRM_MEM_BUFS);
+
        idr_remove(&dev->drw_idr, draw.handle);
-       drm_free(draw_info, sizeof(struct drm_drawable_info), DRM_MEM_BUFS);
 
        spin_unlock_irqrestore(&dev->drw_lock, irqflags);
        DRM_DEBUG("%d\n", draw.handle);
@@ -125,6 +116,13 @@ int drm_update_drawable_info(DRM_IOCTL_ARGS)
                return DRM_ERR(EINVAL);
        }
 
+       if (info == NO_DRW_INFO) {
+               info = drm_calloc(1, sizeof(*info), DRM_MEM_BUFS);
+               if (!info)
+                       return -ENOMEM;
+               idr_replace(&dev->drw_idr, info, update.handle);
+       }
+
        switch (update.type) {
        case DRM_DRAWABLE_CLIPRECTS:
                if (update.num != info->num_rects) {
@@ -187,11 +185,17 @@ drm_drawable_info_t *drm_get_drawable_info(drm_device_t *dev, drm_drawable_t id)
        struct drm_drawable_info *info;
 
        info = idr_find(&dev->drw_idr, id);
+
        if (!info) {
                DRM_DEBUG("No such drawable %d\n", id);
                return NULL;
        }
 
+       if (info == NO_DRW_INFO) {
+               DRM_DEBUG("No information for drawable %d\n", id);
+               return NULL;
+       }
+
        return info;
 }
 EXPORT_SYMBOL(drm_get_drawable_info);
@@ -200,9 +204,12 @@ static int drm_drawable_free(int idr, void *p, void *data)
 {
        struct drm_drawable_info *info = p;
 
-       drm_free(info->rects, info->num_rects *
-                sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
-       drm_free(info, sizeof(struct drm_drawable_info), DRM_MEM_BUFS);
+       if (info != NO_DRW_INFO) {
+               drm_free(info->rects, info->num_rects *
+                        sizeof(drm_clip_rect_t), DRM_MEM_BUFS);
+               drm_free(info, sizeof(*info), DRM_MEM_BUFS);
+       }
+
        return 0;
 }