From 384cc2f9688994dfd505011ba3b08e0a702030b0 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Tue, 20 Nov 2012 12:16:47 +0000 Subject: [PATCH] drm: Add a hash-tab rcu-safe API While hashtab should now be RCU-safe, Add a drm_ht_xxx_api for consumers to use to make it obvious what locking mechanism is used. Document the way the rcu-safe interface should be used. Don't use rcu-safe list traversal in modify operations where we should use a spinlock / mutex anyway. Signed-off-by: Thomas Hellstrom Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_hashtab.c | 26 ++++++++++++++++++++++---- include/drm/drm_hashtab.h | 14 ++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/drm_hashtab.c b/drivers/gpu/drm/drm_hashtab.c index 5729e390aa4e..80254547a3f8 100644 --- a/drivers/gpu/drm/drm_hashtab.c +++ b/drivers/gpu/drm/drm_hashtab.c @@ -67,7 +67,7 @@ void drm_ht_verbose_list(struct drm_open_hash *ht, unsigned long key) hashed_key = hash_long(key, ht->order); DRM_DEBUG("Key is 0x%08lx, Hashed key is 0x%08x\n", key, hashed_key); h_list = &ht->table[hashed_key]; - hlist_for_each_entry_rcu(entry, list, h_list, head) + hlist_for_each_entry(entry, list, h_list, head) DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key); } @@ -79,6 +79,25 @@ static struct hlist_node *drm_ht_find_key(struct drm_open_hash *ht, struct hlist_node *list; unsigned int hashed_key; + hashed_key = hash_long(key, ht->order); + h_list = &ht->table[hashed_key]; + hlist_for_each_entry(entry, list, h_list, head) { + if (entry->key == key) + return list; + if (entry->key > key) + break; + } + return NULL; +} + +static struct hlist_node *drm_ht_find_key_rcu(struct drm_open_hash *ht, + unsigned long key) +{ + struct drm_hash_item *entry; + struct hlist_head *h_list; + struct hlist_node *list; + unsigned int hashed_key; + hashed_key = hash_long(key, ht->order); h_list = &ht->table[hashed_key]; hlist_for_each_entry_rcu(entry, list, h_list, head) { @@ -90,7 +109,6 @@ static struct hlist_node *drm_ht_find_key(struct drm_open_hash *ht, return NULL; } - int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item) { struct drm_hash_item *entry; @@ -102,7 +120,7 @@ int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item) hashed_key = hash_long(key, ht->order); h_list = &ht->table[hashed_key]; parent = NULL; - hlist_for_each_entry_rcu(entry, list, h_list, head) { + hlist_for_each_entry(entry, list, h_list, head) { if (entry->key == key) return -EINVAL; if (entry->key > key) @@ -152,7 +170,7 @@ int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key, { struct hlist_node *list; - list = drm_ht_find_key(ht, key); + list = drm_ht_find_key_rcu(ht, key); if (!list) return -EINVAL; diff --git a/include/drm/drm_hashtab.h b/include/drm/drm_hashtab.h index 3650d5d011ee..fce2ef3fdfff 100644 --- a/include/drm/drm_hashtab.h +++ b/include/drm/drm_hashtab.h @@ -61,5 +61,19 @@ extern int drm_ht_remove_key(struct drm_open_hash *ht, unsigned long key); extern int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item); extern void drm_ht_remove(struct drm_open_hash *ht); +/* + * RCU-safe interface + * + * The user of this API needs to make sure that two or more instances of the + * hash table manipulation functions are never run simultaneously. + * The lookup function drm_ht_find_item_rcu may, however, run simultaneously + * with any of the manipulation functions as long as it's called from within + * an RCU read-locked section. + */ +#define drm_ht_insert_item_rcu drm_ht_insert_item +#define drm_ht_just_insert_please_rcu drm_ht_just_insert_please +#define drm_ht_remove_key_rcu drm_ht_remove_key +#define drm_ht_remove_item_rcu drm_ht_remove_item +#define drm_ht_find_item_rcu drm_ht_find_item #endif