*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; If not, see
- * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * http://www.gnu.org/licenses/gpl-2.0.html
*
* GPL HEADER END
*/
* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2015, Intel Corporation.
+ * Copyright (c) 2011, 2016, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
* table. Also, user can break the iteration by return 1 in callback.
*/
#include <linux/seq_file.h>
+#include <linux/log2.h>
+#include <libcfs/linux/linux-list.h>
#include <libcfs/libcfs.h>
#if CFS_HASH_DEBUG_LEVEL >= CFS_HASH_DEBUG_1
}
EXPORT_SYMBOL(cfs_hash_bd_peek_locked);
-struct hlist_node *
-cfs_hash_bd_findadd_locked(struct cfs_hash *hs, struct cfs_hash_bd *bd,
- const void *key, struct hlist_node *hnode,
- int noref)
-{
- return cfs_hash_bd_lookup_intent(hs, bd, key, hnode,
- CFS_HS_LOOKUP_IT_ADD |
- (!noref * CFS_HS_LOOKUP_MASK_REF));
-}
-
-struct hlist_node *
-cfs_hash_bd_finddel_locked(struct cfs_hash *hs, struct cfs_hash_bd *bd,
- const void *key, struct hlist_node *hnode)
-{
- /* hnode can be NULL, we find the first item with @key */
- return cfs_hash_bd_lookup_intent(hs, bd, key, hnode,
- CFS_HS_LOOKUP_IT_FINDDEL);
-}
-
static void
cfs_hash_multi_bd_lock(struct cfs_hash *hs, struct cfs_hash_bd *bds,
unsigned n, int excl)
if (rc == 0) {
bd2->bd_bucket = NULL;
- } else if (rc > 0) { /* swab bd1 and bd2 */
- struct cfs_hash_bd tmp;
-
- tmp = *bd2;
- *bd2 = *bd1;
- *bd1 = tmp;
+ } else if (rc > 0) {
+ swap(*bd1, *bd2); /* swab bd1 and bd2 */
}
}
LASSERT(ops->hs_object);
LASSERT(ops->hs_keycmp);
LASSERT(ops->hs_get != NULL);
- LASSERT(ops->hs_put_locked != NULL);
+ LASSERT(ops->hs_put != NULL || ops->hs_put_locked != NULL);
if ((flags & CFS_HASH_REHASH) != 0)
flags |= CFS_HASH_COUNTER; /* must have counter */
struct cfs_hash_bd bds[2];
int bits = 0;
- LASSERT(hlist_unhashed(hnode));
+ LASSERTF(hlist_unhashed(hnode), "hnode = %p\n", hnode);
- cfs_hash_lock(hs, 0);
- cfs_hash_dual_bd_get_and_lock(hs, key, bds, 1);
+ cfs_hash_lock(hs, 0);
+ cfs_hash_dual_bd_get_and_lock(hs, key, bds, 1);
- cfs_hash_key_validate(hs, key, hnode);
- ehnode = cfs_hash_dual_bd_findadd_locked(hs, bds, key,
- hnode, noref);
- cfs_hash_dual_bd_unlock(hs, bds, 1);
+ cfs_hash_key_validate(hs, key, hnode);
+ ehnode = cfs_hash_dual_bd_findadd_locked(hs, bds, key,
+ hnode, noref);
+ cfs_hash_dual_bd_unlock(hs, bds, 1);
- if (ehnode == hnode) /* new item added */
- bits = cfs_hash_rehash_bits(hs);
- cfs_hash_unlock(hs, 0);
- if (bits > 0)
- cfs_hash_rehash(hs, cfs_hash_rehash_inline(hs));
+ if (ehnode == hnode) /* new item added */
+ bits = cfs_hash_rehash_bits(hs);
+ cfs_hash_unlock(hs, 0);
+ if (bits > 0)
+ cfs_hash_rehash(hs, cfs_hash_rehash_inline(hs));
- return ehnode;
+ return ehnode;
}
/**
void *data, int start)
{
struct hlist_node *hnode;
- struct hlist_node *tmp;
+ struct hlist_node *next = NULL;
struct cfs_hash_bd bd;
__u32 version;
int count = 0;
int stop_on_change;
+ int has_put_locked;
int rc = 0;
int i, end = -1;
ENTRY;
stop_on_change = cfs_hash_with_rehash_key(hs) ||
- !cfs_hash_with_no_itemref(hs) ||
- hs->hs_ops->hs_put_locked == NULL;
+ !cfs_hash_with_no_itemref(hs);
+ has_put_locked = hs->hs_ops->hs_put_locked != NULL;
cfs_hash_lock(hs, 0);
again:
LASSERT(!cfs_hash_is_rehashing(hs));
version = cfs_hash_bd_version_get(&bd);
cfs_hash_bd_for_each_hlist(hs, &bd, hhead) {
- for (hnode = hhead->first; hnode != NULL;) {
- cfs_hash_bucket_validate(hs, &bd, hnode);
- cfs_hash_get(hs, hnode);
+ hnode = hhead->first;
+ if (hnode == NULL)
+ continue;
+ cfs_hash_get(hs, hnode);
+ for (; hnode != NULL; hnode = next) {
+ cfs_hash_bucket_validate(hs, &bd, hnode);
+ next = hnode->next;
+ if (next != NULL)
+ cfs_hash_get(hs, next);
cfs_hash_bd_unlock(hs, &bd, 0);
cfs_hash_unlock(hs, 0);
rc = func(hs, &bd, hnode, data);
- if (stop_on_change)
+ if (stop_on_change || !has_put_locked)
cfs_hash_put(hs, hnode);
+
cond_resched();
count++;
cfs_hash_lock(hs, 0);
cfs_hash_bd_lock(hs, &bd, 0);
- if (!stop_on_change) {
- tmp = hnode->next;
- cfs_hash_put_locked(hs, hnode);
- hnode = tmp;
- } else { /* bucket changed? */
- if (version !=
- cfs_hash_bd_version_get(&bd))
- break;
- /* safe to continue because no change */
- hnode = hnode->next;
- }
+ if (stop_on_change) {
+ if (version !=
+ cfs_hash_bd_version_get(&bd))
+ rc = -EINTR;
+ } else if (has_put_locked) {
+ cfs_hash_put_locked(hs, hnode);
+ }
if (rc) /* callback wants to break iteration */
break;
}
- if (rc) /* callback wants to break iteration */
+ if (next != NULL) {
+ if (has_put_locked) {
+ cfs_hash_put_locked(hs, next);
+ next = NULL;
+ }
+ break;
+ } else if (rc != 0) {
break;
+ }
}
cfs_hash_bd_unlock(hs, &bd, 0);
+ if (next != NULL && !has_put_locked) {
+ cfs_hash_put(hs, next);
+ next = NULL;
+ }
if (rc) /* callback wants to break iteration */
break;
}
for (i = 2; cfs_hash_is_rehashing(hs); i++) {
cfs_hash_unlock(hs, 1);
/* raise console warning while waiting too long */
- CDEBUG(IS_PO2(i >> 3) ? D_WARNING : D_INFO,
+ CDEBUG(is_power_of_2(i >> 3) ? D_WARNING : D_INFO,
"hash %s is still rehashing, rescheded %d\n",
hs->hs_name, i - 1);
cond_resched();
}
EXPORT_SYMBOL(cfs_hash_rehash_key);
-int cfs_hash_debug_header(struct seq_file *m)
+void cfs_hash_debug_header(struct seq_file *m)
{
- return seq_printf(m, "%-*s%6s%6s%6s%6s%6s%6s%6s%7s%8s%8s%8s%s\n",
- CFS_HASH_BIGNAME_LEN,
- "name", "cur", "min", "max", "theta", "t-min", "t-max",
- "flags", "rehash", "count", "maxdep", "maxdepb",
- " distribution");
+ seq_printf(m, "%-*s cur min max theta t-min t-max flags rehash count maxdep maxdepb distribution\n",
+ CFS_HASH_BIGNAME_LEN, "name");
}
EXPORT_SYMBOL(cfs_hash_debug_header);
CFS_HASH_RH_NBKT(hs) : CFS_HASH_NBKT(hs);
}
-int cfs_hash_debug_str(struct cfs_hash *hs, struct seq_file *m)
+void cfs_hash_debug_str(struct cfs_hash *hs, struct seq_file *m)
{
- int dist[8] = { 0, };
- int maxdep = -1;
- int maxdepb = -1;
- int total = 0;
- int c = 0;
- int theta;
- int i;
+ int dist[8] = { 0, };
+ int maxdep = -1;
+ int maxdepb = -1;
+ int total = 0;
+ int theta;
+ int i;
cfs_hash_lock(hs, 0);
theta = __cfs_hash_theta(hs);
- c += seq_printf(m, "%-*s ", CFS_HASH_BIGNAME_LEN, hs->hs_name);
- c += seq_printf(m, "%5d ", 1 << hs->hs_cur_bits);
- c += seq_printf(m, "%5d ", 1 << hs->hs_min_bits);
- c += seq_printf(m, "%5d ", 1 << hs->hs_max_bits);
- c += seq_printf(m, "%d.%03d ", __cfs_hash_theta_int(theta),
- __cfs_hash_theta_frac(theta));
- c += seq_printf(m, "%d.%03d ", __cfs_hash_theta_int(hs->hs_min_theta),
- __cfs_hash_theta_frac(hs->hs_min_theta));
- c += seq_printf(m, "%d.%03d ", __cfs_hash_theta_int(hs->hs_max_theta),
- __cfs_hash_theta_frac(hs->hs_max_theta));
- c += seq_printf(m, " 0x%02x ", hs->hs_flags);
- c += seq_printf(m, "%6d ", hs->hs_rehash_count);
+ seq_printf(m, "%-*s %5d %5d %5d %d.%03d %d.%03d %d.%03d 0x%02x %6d ",
+ CFS_HASH_BIGNAME_LEN, hs->hs_name,
+ 1 << hs->hs_cur_bits, 1 << hs->hs_min_bits,
+ 1 << hs->hs_max_bits,
+ __cfs_hash_theta_int(theta), __cfs_hash_theta_frac(theta),
+ __cfs_hash_theta_int(hs->hs_min_theta),
+ __cfs_hash_theta_frac(hs->hs_min_theta),
+ __cfs_hash_theta_int(hs->hs_max_theta),
+ __cfs_hash_theta_frac(hs->hs_max_theta),
+ hs->hs_flags, hs->hs_rehash_count);
/*
* The distribution is a summary of the chained hash depth in
maxdepb = ffz(~maxdep);
}
total += bd.bd_bucket->hsb_count;
- dist[min(fls(bd.bd_bucket->hsb_count/max(theta,1)),7)]++;
+ dist[min(fls(bd.bd_bucket->hsb_count / max(theta, 1)), 7)]++;
cfs_hash_bd_unlock(hs, &bd, 0);
}
- c += seq_printf(m, "%7d ", total);
- c += seq_printf(m, "%7d ", maxdep);
- c += seq_printf(m, "%7d ", maxdepb);
+ seq_printf(m, "%7d %7d %7d ", total, maxdep, maxdepb);
for (i = 0; i < 8; i++)
- c += seq_printf(m, "%d%c", dist[i], (i == 7) ? '\n' : '/');
+ seq_printf(m, "%d%c", dist[i], (i == 7) ? '\n' : '/');
cfs_hash_unlock(hs, 0);
- return c;
}
EXPORT_SYMBOL(cfs_hash_debug_str);