drm: move drm authentication to new generic hash table.
authorThomas Hellstrom <thomas@tungstengraphics.com>
Mon, 7 Aug 2006 12:22:10 +0000 (22:22 +1000)
committerDave Airlie <airlied@linux.ie>
Thu, 21 Sep 2006 19:32:31 +0000 (05:32 +1000)
Fix drm_remove_magic potential memory leak / corruption. Move drm
authentication token hashing to new generic hash table implementation.

Signed-off-by: Dave Airlie <airlied@linux.ie>
drivers/char/drm/drmP.h
drivers/char/drm/drm_auth.c
drivers/char/drm/drm_drv.c
drivers/char/drm/drm_fops.c
drivers/char/drm/drm_hashtab.h

index c93985bb91a20912a824c32f6613ffda23ca1aa2..fedaf013f848704b2f558c0b785b9aefc3bdd951 100644 (file)
 #define DRM_DEBUG_CODE 2         /**< Include debugging code if > 1, then
                                     also include looping detection. */
 
-#define DRM_HASH_SIZE        16 /**< Size of key hash table. Must be power of 2. */
+#define DRM_MAGIC_HASH_ORDER  4  /**< Size of key hash table. Must be power of 2. */
 #define DRM_KERNEL_CONTEXT    0         /**< Change drm_resctx if changed */
 #define DRM_RESERVED_CONTEXTS 1         /**< Change drm_resctx if changed */
 #define DRM_LOOPING_LIMIT     5000000
@@ -277,7 +277,8 @@ typedef struct drm_devstate {
 } drm_devstate_t;
 
 typedef struct drm_magic_entry {
-       drm_magic_t magic;
+       drm_hash_item_t hash_item;
+       struct list_head head;
        struct drm_file *priv;
        struct drm_magic_entry *next;
 } drm_magic_entry_t;
@@ -653,7 +654,8 @@ typedef struct drm_device {
        /*@{ */
        drm_file_t *file_first;         /**< file list head */
        drm_file_t *file_last;          /**< file list tail */
-       drm_magic_head_t magiclist[DRM_HASH_SIZE];      /**< magic hash table */
+       drm_open_hash_t magiclist;      /**< magic hash table */
+       struct list_head magicfree;
        /*@} */
 
        /** \name Memory management */
index 2a37586a7ee8d4e7ca856723f27be808e6649005..40cd262ca9e1b2009d0171f810a145afc0a7c50b 100644 (file)
 
 #include "drmP.h"
 
-/**
- * Generate a hash key from a magic.
- *
- * \param magic magic.
- * \return hash key.
- *
- * The key is the modulus of the hash table size, #DRM_HASH_SIZE, which must be
- * a power of 2.
- */
-static int drm_hash_magic(drm_magic_t magic)
-{
-       return magic & (DRM_HASH_SIZE - 1);
-}
-
 /**
  * Find the file with the given magic number.
  *
@@ -63,14 +49,12 @@ static drm_file_t *drm_find_file(drm_device_t * dev, drm_magic_t magic)
 {
        drm_file_t *retval = NULL;
        drm_magic_entry_t *pt;
-       int hash = drm_hash_magic(magic);
+       drm_hash_item_t *hash;
 
        mutex_lock(&dev->struct_mutex);
-       for (pt = dev->magiclist[hash].head; pt; pt = pt->next) {
-               if (pt->magic == magic) {
-                       retval = pt->priv;
-                       break;
-               }
+       if (!drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) {
+               pt = drm_hash_entry(hash, drm_magic_entry_t, hash_item);
+               retval = pt->priv;
        }
        mutex_unlock(&dev->struct_mutex);
        return retval;
@@ -90,28 +74,20 @@ static drm_file_t *drm_find_file(drm_device_t * dev, drm_magic_t magic)
 static int drm_add_magic(drm_device_t * dev, drm_file_t * priv,
                         drm_magic_t magic)
 {
-       int hash;
        drm_magic_entry_t *entry;
 
        DRM_DEBUG("%d\n", magic);
 
-       hash = drm_hash_magic(magic);
        entry = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC);
        if (!entry)
                return -ENOMEM;
        memset(entry, 0, sizeof(*entry));
-       entry->magic = magic;
        entry->priv = priv;
-       entry->next = NULL;
 
+       entry->hash_item.key = (unsigned long)magic;
        mutex_lock(&dev->struct_mutex);
-       if (dev->magiclist[hash].tail) {
-               dev->magiclist[hash].tail->next = entry;
-               dev->magiclist[hash].tail = entry;
-       } else {
-               dev->magiclist[hash].head = entry;
-               dev->magiclist[hash].tail = entry;
-       }
+       drm_ht_insert_item(&dev->magiclist, &entry->hash_item);
+       list_add_tail(&entry->head, &dev->magicfree);
        mutex_unlock(&dev->struct_mutex);
 
        return 0;
@@ -128,29 +104,19 @@ static int drm_add_magic(drm_device_t * dev, drm_file_t * priv,
  */
 static int drm_remove_magic(drm_device_t * dev, drm_magic_t magic)
 {
-       drm_magic_entry_t *prev = NULL;
        drm_magic_entry_t *pt;
-       int hash;
+       drm_hash_item_t *hash;
 
        DRM_DEBUG("%d\n", magic);
-       hash = drm_hash_magic(magic);
 
        mutex_lock(&dev->struct_mutex);
-       for (pt = dev->magiclist[hash].head; pt; prev = pt, pt = pt->next) {
-               if (pt->magic == magic) {
-                       if (dev->magiclist[hash].head == pt) {
-                               dev->magiclist[hash].head = pt->next;
-                       }
-                       if (dev->magiclist[hash].tail == pt) {
-                               dev->magiclist[hash].tail = prev;
-                       }
-                       if (prev) {
-                               prev->next = pt->next;
-                       }
-                       mutex_unlock(&dev->struct_mutex);
-                       return 0;
-               }
+       if (drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) {
+               mutex_unlock(&dev->struct_mutex);
+               return -EINVAL;
        }
+       pt = drm_hash_entry(hash, drm_magic_entry_t, hash_item);
+       drm_ht_remove_item(&dev->magiclist, hash);
+       list_del(&pt->head);
        mutex_unlock(&dev->struct_mutex);
 
        drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
index 3da72f7364f00c52eae0c362532420470e1668d1..f9ecc8414b8a962d7773276485b5367e9b99cbef 100644 (file)
@@ -155,12 +155,10 @@ int drm_lastclose(drm_device_t * dev)
        del_timer(&dev->timer);
 
        /* Clear pid list */
-       for (i = 0; i < DRM_HASH_SIZE; i++) {
-               for (pt = dev->magiclist[i].head; pt; pt = next) {
-                       next = pt->next;
-                       drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
-               }
-               dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
+       list_for_each_entry_safe(pt, next, &dev->magicfree, head) {
+               list_del(&pt->head);
+               drm_ht_remove_item(&dev->magiclist, &pt->hash_item);
+               drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
        }
 
        /* Clear AGP information */
index 51ccc82bf612dacd2ec95e753dcaafffea6815ab..2bbf45d85c35fab53ba3038241d30988f9fab8bd 100644 (file)
@@ -72,10 +72,8 @@ static int drm_setup(drm_device_t * dev)
        for (i = 0; i < ARRAY_SIZE(dev->counts); i++)
                atomic_set(&dev->counts[i], 0);
 
-       for (i = 0; i < DRM_HASH_SIZE; i++) {
-               dev->magiclist[i].head = NULL;
-               dev->magiclist[i].tail = NULL;
-       }
+       drm_ht_create(&dev->magiclist, DRM_MAGIC_HASH_ORDER);
+       INIT_LIST_HEAD(&dev->magicfree);
 
        dev->ctxlist = drm_alloc(sizeof(*dev->ctxlist), DRM_MEM_CTXLIST);
        if (dev->ctxlist == NULL)
index 40afec05bff80fd37ec9e90332275cbcbfc263d6..9e19ef1814baacb56d3ae7b833b2136905d58db3 100644 (file)
@@ -35,7 +35,7 @@
 #ifndef DRM_HASHTAB_H
 #define DRM_HASHTAB_H
 
-#define drm_hash_entry(_ptr, _type, _member) container_of(_ptr, _type, _member)
+#define drm_hash_entry(_ptr, _type, _member) list_entry(_ptr, _type, _member)
 
 typedef struct drm_hash_item{
        struct hlist_node head;