diff options
author | Thomas Hellstrom <thellstrom@vmware.com> | 2012-11-20 07:16:47 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2012-11-28 03:36:05 -0500 |
commit | 384cc2f9688994dfd505011ba3b08e0a702030b0 (patch) | |
tree | 9d7f8d1f3a68d88442d35cd13a67563571147f29 | |
parent | 7e8d9da32ea02f02a23f998cd2013408a4fe49bb (diff) |
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 <thellstrom@vmware.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r-- | drivers/gpu/drm/drm_hashtab.c | 26 | ||||
-rw-r--r-- | 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) | |||
67 | hashed_key = hash_long(key, ht->order); | 67 | hashed_key = hash_long(key, ht->order); |
68 | DRM_DEBUG("Key is 0x%08lx, Hashed key is 0x%08x\n", key, hashed_key); | 68 | DRM_DEBUG("Key is 0x%08lx, Hashed key is 0x%08x\n", key, hashed_key); |
69 | h_list = &ht->table[hashed_key]; | 69 | h_list = &ht->table[hashed_key]; |
70 | hlist_for_each_entry_rcu(entry, list, h_list, head) | 70 | hlist_for_each_entry(entry, list, h_list, head) |
71 | DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key); | 71 | DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key); |
72 | } | 72 | } |
73 | 73 | ||
@@ -81,7 +81,7 @@ static struct hlist_node *drm_ht_find_key(struct drm_open_hash *ht, | |||
81 | 81 | ||
82 | hashed_key = hash_long(key, ht->order); | 82 | hashed_key = hash_long(key, ht->order); |
83 | h_list = &ht->table[hashed_key]; | 83 | h_list = &ht->table[hashed_key]; |
84 | hlist_for_each_entry_rcu(entry, list, h_list, head) { | 84 | hlist_for_each_entry(entry, list, h_list, head) { |
85 | if (entry->key == key) | 85 | if (entry->key == key) |
86 | return list; | 86 | return list; |
87 | if (entry->key > key) | 87 | if (entry->key > key) |
@@ -90,6 +90,24 @@ static struct hlist_node *drm_ht_find_key(struct drm_open_hash *ht, | |||
90 | return NULL; | 90 | return NULL; |
91 | } | 91 | } |
92 | 92 | ||
93 | static struct hlist_node *drm_ht_find_key_rcu(struct drm_open_hash *ht, | ||
94 | unsigned long key) | ||
95 | { | ||
96 | struct drm_hash_item *entry; | ||
97 | struct hlist_head *h_list; | ||
98 | struct hlist_node *list; | ||
99 | unsigned int hashed_key; | ||
100 | |||
101 | hashed_key = hash_long(key, ht->order); | ||
102 | h_list = &ht->table[hashed_key]; | ||
103 | hlist_for_each_entry_rcu(entry, list, h_list, head) { | ||
104 | if (entry->key == key) | ||
105 | return list; | ||
106 | if (entry->key > key) | ||
107 | break; | ||
108 | } | ||
109 | return NULL; | ||
110 | } | ||
93 | 111 | ||
94 | int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item) | 112 | int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item) |
95 | { | 113 | { |
@@ -102,7 +120,7 @@ int drm_ht_insert_item(struct drm_open_hash *ht, struct drm_hash_item *item) | |||
102 | hashed_key = hash_long(key, ht->order); | 120 | hashed_key = hash_long(key, ht->order); |
103 | h_list = &ht->table[hashed_key]; | 121 | h_list = &ht->table[hashed_key]; |
104 | parent = NULL; | 122 | parent = NULL; |
105 | hlist_for_each_entry_rcu(entry, list, h_list, head) { | 123 | hlist_for_each_entry(entry, list, h_list, head) { |
106 | if (entry->key == key) | 124 | if (entry->key == key) |
107 | return -EINVAL; | 125 | return -EINVAL; |
108 | if (entry->key > key) | 126 | if (entry->key > key) |
@@ -152,7 +170,7 @@ int drm_ht_find_item(struct drm_open_hash *ht, unsigned long key, | |||
152 | { | 170 | { |
153 | struct hlist_node *list; | 171 | struct hlist_node *list; |
154 | 172 | ||
155 | list = drm_ht_find_key(ht, key); | 173 | list = drm_ht_find_key_rcu(ht, key); |
156 | if (!list) | 174 | if (!list) |
157 | return -EINVAL; | 175 | return -EINVAL; |
158 | 176 | ||
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); | |||
61 | extern int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item); | 61 | extern int drm_ht_remove_item(struct drm_open_hash *ht, struct drm_hash_item *item); |
62 | extern void drm_ht_remove(struct drm_open_hash *ht); | 62 | extern void drm_ht_remove(struct drm_open_hash *ht); |
63 | 63 | ||
64 | /* | ||
65 | * RCU-safe interface | ||
66 | * | ||
67 | * The user of this API needs to make sure that two or more instances of the | ||
68 | * hash table manipulation functions are never run simultaneously. | ||
69 | * The lookup function drm_ht_find_item_rcu may, however, run simultaneously | ||
70 | * with any of the manipulation functions as long as it's called from within | ||
71 | * an RCU read-locked section. | ||
72 | */ | ||
73 | #define drm_ht_insert_item_rcu drm_ht_insert_item | ||
74 | #define drm_ht_just_insert_please_rcu drm_ht_just_insert_please | ||
75 | #define drm_ht_remove_key_rcu drm_ht_remove_key | ||
76 | #define drm_ht_remove_item_rcu drm_ht_remove_item | ||
77 | #define drm_ht_find_item_rcu drm_ht_find_item | ||
64 | 78 | ||
65 | #endif | 79 | #endif |