summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorOwain Ainsworth <oga@cvs.openbsd.org>2008-04-12 14:14:03 +0000
committerOwain Ainsworth <oga@cvs.openbsd.org>2008-04-12 14:14:03 +0000
commit22a3a1e6d4f41d3dc4b564e66874943ec62688d7 (patch)
treeb2002c350b1a99afdcfef3013dadd8d61b99f63b /sys/dev
parent027b1334162c3cbaf6167038026b6d7354256093 (diff)
Make sure that the drawables are properly freed when removed, and upon
last close of the device nuke them all. Inspired by similar code in the linux drm driver. Tested by many.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/drm/drmP.h1
-rw-r--r--sys/dev/pci/drm/drm_drawable.c70
-rw-r--r--sys/dev/pci/drm/drm_drv.c2
3 files changed, 58 insertions, 15 deletions
diff --git a/sys/dev/pci/drm/drmP.h b/sys/dev/pci/drm/drmP.h
index c9a2b235992..09f0627976f 100644
--- a/sys/dev/pci/drm/drmP.h
+++ b/sys/dev/pci/drm/drmP.h
@@ -1095,6 +1095,7 @@ int drm_getsareactx(drm_device_t *dev, void *data, struct drm_file *file_priv);
int drm_adddraw(drm_device_t *dev, void *data, struct drm_file *file_priv);
int drm_rmdraw(drm_device_t *dev, void *data, struct drm_file *file_priv);
int drm_update_draw(drm_device_t *dev, void *data, struct drm_file *file_priv);
+void drm_drawable_free_all(struct drm_device *);
struct drm_drawable_info *drm_get_drawable_info(drm_device_t *dev, int handle);
/* Authentication IOCTL support (drm_auth.c) */
diff --git a/sys/dev/pci/drm/drm_drawable.c b/sys/dev/pci/drm/drm_drawable.c
index 021f348136e..306f4bf5627 100644
--- a/sys/dev/pci/drm/drm_drawable.c
+++ b/sys/dev/pci/drm/drm_drawable.c
@@ -35,8 +35,14 @@
#include "drmP.h"
+struct bsd_drm_drawable_info;
+
int drm_drawable_compare(struct bsd_drm_drawable_info *,
struct bsd_drm_drawable_info *);
+void drm_drawable_free(struct drm_device *dev,
+ struct bsd_drm_drawable_info *draw);
+struct bsd_drm_drawable_info *
+ drm_get_drawable(struct drm_device *, int);
#ifdef __OpenBSD__
RB_PROTOTYPE(drawable_tree, bsd_drm_drawable_info, tree,
@@ -68,18 +74,24 @@ RB_GENERATE(drawable_tree, bsd_drm_drawable_info, tree,
drm_drawable_compare);
#endif
-struct drm_drawable_info *
-drm_get_drawable_info(drm_device_t *dev, int handle)
+struct bsd_drm_drawable_info *
+drm_get_drawable(struct drm_device *dev, int handle)
{
- struct bsd_drm_drawable_info find, *result = NULL;
+ struct bsd_drm_drawable_info find;
find.handle = handle;
- result = RB_FIND(drawable_tree, &dev->drw_head, &find);
+ return (RB_FIND(drawable_tree, &dev->drw_head, &find));
+}
+
+struct drm_drawable_info *
+drm_get_drawable_info(drm_device_t *dev, int handle)
+{
+ struct bsd_drm_drawable_info *result = NULL;
- if (result)
+ if ((result = drm_get_drawable(dev, handle)))
return &result->info;
- return NULL;
+ return (NULL);
}
int
@@ -112,19 +124,13 @@ int
drm_rmdraw(drm_device_t *dev, void *data, struct drm_file *file_priv)
{
drm_draw_t *draw = (drm_draw_t *)data;
- struct drm_drawable_info *info;
+ struct bsd_drm_drawable_info *info;
DRM_SPINLOCK(&dev->drw_lock);
- info = drm_get_drawable_info(dev, draw->handle);
+ info = drm_get_drawable(dev, draw->handle);
if (info != NULL) {
- RB_REMOVE(drawable_tree, &dev->drw_head,
- (struct bsd_drm_drawable_info *)info);
+ drm_drawable_free(dev, info);
DRM_SPINUNLOCK(&dev->drw_lock);
-#ifdef __FreeBSD__
- free_unr(dev->drw_unrhdr, draw->handle);
-#endif
- drm_free(info, sizeof(struct bsd_drm_drawable_info),
- DRM_MEM_DRAWABLE);
return 0;
} else {
DRM_SPINUNLOCK(&dev->drw_lock);
@@ -176,3 +182,37 @@ drm_update_draw(drm_device_t *dev, void *data, struct drm_file *file_priv)
return EINVAL;
}
}
+
+void
+drm_drawable_free(struct drm_device *dev, struct bsd_drm_drawable_info *draw)
+{
+ if (draw) {
+ RB_REMOVE(drawable_tree, &dev->drw_head, draw);
+ if (draw->info.rects)
+ drm_free(draw->info.rects,
+ sizeof(*draw->info.rects) * draw->info.num_rects,
+ DRM_MEM_DRAWABLE);
+#ifdef __FreeBSD__
+ free_unr(dev->drw_unrhdr, draw->info->handle);
+#endif
+ drm_free(draw, sizeof(*draw),
+ DRM_MEM_DRAWABLE);
+ }
+}
+
+void
+drm_drawable_free_all(struct drm_device *dev)
+{
+ struct bsd_drm_drawable_info *draw, *nxt;
+
+ DRM_SPINLOCK(&dev->drw_lock);
+
+ for (draw = RB_MIN(drawable_tree, &dev->drw_head); draw != NULL;
+ draw = nxt) {
+ nxt = RB_NEXT(drawable_tree, &dev->drw_head, draw);
+ drm_drawable_free(dev, draw);
+
+ }
+ DRM_SPINUNLOCK(&dev->drw_lock);
+
+}
diff --git a/sys/dev/pci/drm/drm_drv.c b/sys/dev/pci/drm/drm_drv.c
index a36ac17f9fb..0be2df47f88 100644
--- a/sys/dev/pci/drm/drm_drv.c
+++ b/sys/dev/pci/drm/drm_drv.c
@@ -426,6 +426,8 @@ drm_lastclose(drm_device_t *dev)
dev->unique = NULL;
dev->unique_len = 0;
}
+
+ drm_drawable_free_all(dev);
/* Clear pid list */
for ( i = 0 ; i < DRM_HASH_SIZE ; i++ ) {
while ((pt = TAILQ_FIRST(&dev->magiclist[i])) != NULL) {