#include <libcfs/libcfs.h>
+static void cfs_hash_destroy(cfs_hash_t *hs);
+
static void
cfs_hash_rlock(cfs_hash_t *hs)
{
LASSERT(name != NULL);
LASSERT(ops != NULL);
+ /* The following ops are required for all hash table types */
+ LASSERT(ops->hs_hash != NULL);
+ LASSERT(ops->hs_key != NULL);
+ LASSERT(ops->hs_compare != NULL);
+ LASSERT(ops->hs_get != NULL);
+ LASSERT(ops->hs_put != NULL);
LASSERT(cur_bits > 0);
LASSERT(max_bits >= cur_bits);
strncpy(hs->hs_name, name, sizeof(hs->hs_name));
hs->hs_name[sizeof(hs->hs_name) - 1] = '\0';
cfs_atomic_set(&hs->hs_rehash_count, 0);
+ cfs_atomic_set(&hs->hs_refcount, 1);
cfs_atomic_set(&hs->hs_count, 0);
cfs_rwlock_init(&hs->hs_rwlock);
hs->hs_cur_bits = cur_bits;
/**
* Cleanup libcfs hash @hs.
*/
-void
+static void
cfs_hash_destroy(cfs_hash_t *hs)
{
cfs_hash_bucket_t *hsb;
CFS_FREE_PTR(hs);
EXIT;
}
-CFS_EXPORT_SYMBOL(cfs_hash_destroy);
+
+cfs_hash_t *cfs_hash_getref(cfs_hash_t *hs)
+{
+ if (cfs_atomic_inc_not_zero(&hs->hs_refcount))
+ return hs;
+ return NULL;
+}
+CFS_EXPORT_SYMBOL(cfs_hash_getref);
+
+void cfs_hash_putref(cfs_hash_t *hs)
+{
+ if (cfs_atomic_dec_and_test(&hs->hs_refcount))
+ cfs_hash_destroy(hs);
+}
+CFS_EXPORT_SYMBOL(cfs_hash_putref);
static inline unsigned int
cfs_hash_rehash_bits(cfs_hash_t *hs)
{
cfs_hlist_node_t *hnode;
cfs_hash_bucket_t *hsb;
+ cfs_hash_bucket_t **hsb_last = NULL;
void *obj;
- int i;
+ int i = 0;
ENTRY;
restart:
cfs_hash_rlock(hs);
- cfs_hash_for_each_bucket(hs, hsb, i) {
+ /* If the hash table has changed since we last held lh_rwlock,
+ * we need to start traversing the list from the start. */
+ if (hs->hs_buckets != hsb_last) {
+ i = 0;
+ hsb_last = hs->hs_buckets;
+ }
+ cfs_hash_for_each_bucket_restart(hs, hsb, i) {
cfs_write_lock(&hsb->hsb_rwlock);
while (!cfs_hlist_empty(&hsb->hsb_head)) {
hnode = hsb->hsb_head.first;