diff options
author | Owain Ainsworth <oga@cvs.openbsd.org> | 2008-04-12 14:14:03 +0000 |
---|---|---|
committer | Owain Ainsworth <oga@cvs.openbsd.org> | 2008-04-12 14:14:03 +0000 |
commit | 22a3a1e6d4f41d3dc4b564e66874943ec62688d7 (patch) | |
tree | b2002c350b1a99afdcfef3013dadd8d61b99f63b /sys/dev | |
parent | 027b1334162c3cbaf6167038026b6d7354256093 (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.h | 1 | ||||
-rw-r--r-- | sys/dev/pci/drm/drm_drawable.c | 70 | ||||
-rw-r--r-- | sys/dev/pci/drm/drm_drv.c | 2 |
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) { |