Whamcloud - gitweb
b=22683 remove unnecessary check and assert in the cfs_hash function.
[fs/lustre-release.git] / libcfs / libcfs / hash.c
index 56e2df5..ae2f640 100644 (file)
@@ -57,6 +57,8 @@
 
 #include <libcfs/libcfs.h>
 
+static void cfs_hash_destroy(cfs_hash_t *hs);
+
 static void
 cfs_hash_rlock(cfs_hash_t *hs)
 {
@@ -104,6 +106,12 @@ cfs_hash_create(char *name, unsigned int cur_bits,
 
         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);
@@ -117,6 +125,7 @@ cfs_hash_create(char *name, unsigned int 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;
@@ -159,7 +168,7 @@ CFS_EXPORT_SYMBOL(cfs_hash_create);
 /**
  * Cleanup libcfs hash @hs.
  */
-void
+static void
 cfs_hash_destroy(cfs_hash_t *hs)
 {
         cfs_hash_bucket_t    *hsb;
@@ -197,7 +206,21 @@ cfs_hash_destroy(cfs_hash_t *hs)
         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)
@@ -515,13 +538,20 @@ cfs_hash_for_each_empty(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;