1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (C) 2005 Cluster File Systems, Inc.
5 * Author: YuZhangyong <yzy@clusterfs.com>
7 * This file is part of Lustre, http://www.lustre.org/
9 * No redistribution or use is permitted outside of Cluster File Systems, Inc.
11 * Implement a hash class for hash process in lustre system.
15 #include <liblustre.h>
19 #include <obd_class.h>
20 #include <class_hash.h>
21 #include <lustre_export.h>
22 #include <obd_support.h>
23 #include <lustre_net.h>
24 #include <lustre_quota.h>
26 int lustre_hash_init(struct lustre_class_hash_body **hash_body_new,
27 char *hashname, __u32 hashsize,
28 struct lustre_hash_operations *hash_operations)
31 struct lustre_class_hash_body *hash_body = NULL;
33 LASSERT(hashsize > 0);
34 LASSERT(hash_operations != NULL);
44 LASSERTF(n == 1, "hashsize %u isn't 2^n\n", hashsize);
46 /* alloc space for hash_body */
47 OBD_ALLOC(hash_body, sizeof(*hash_body));
49 if (hash_body == NULL) {
50 CERROR("Cannot alloc space for hash body, hashname = %s \n",
55 LASSERT(hashname != NULL &&
56 strlen(hashname) <= sizeof(hash_body->hashname));
57 strcpy(hash_body->hashname, hashname);
58 hash_body->lchb_hash_max_size = hashsize;
59 hash_body->lchb_hash_operations = hash_operations;
61 /* alloc space for the hash tables */
62 OBD_ALLOC(hash_body->lchb_hash_tables,
63 sizeof(*hash_body->lchb_hash_tables) * hash_body->lchb_hash_max_size);
65 if (hash_body->lchb_hash_tables == NULL) {
66 OBD_FREE(hash_body, sizeof(*hash_body));
67 CERROR("Cannot alloc space for hashtables, hashname = %s \n",
72 spin_lock_init(&hash_body->lchb_lock); /* initialize the body lock */
74 for(i = 0 ; i < hash_body->lchb_hash_max_size; i++) {
75 /* initial the bucket lock and list_head */
76 INIT_HLIST_HEAD(&hash_body->lchb_hash_tables[i].lhb_head);
77 spin_lock_init(&hash_body->lchb_hash_tables[i].lhb_lock);
79 *hash_body_new = hash_body;
83 EXPORT_SYMBOL(lustre_hash_init);
85 void lustre_hash_exit(struct lustre_class_hash_body **new_hash_body)
88 struct lustre_class_hash_body *hash_body = NULL;
91 hash_body = *new_hash_body;
93 if (hash_body == NULL) {
94 CWARN("hash body has been deleted\n");
98 spin_lock(&hash_body->lchb_lock); /* lock the hash tables */
100 if (hash_body->lchb_hash_tables == NULL ) {
101 spin_unlock(&hash_body->lchb_lock);
102 CWARN("hash tables has been deleted\n");
106 for( i = 0; i < hash_body->lchb_hash_max_size; i++ ) {
107 struct lustre_hash_bucket * bucket;
108 struct hlist_node * actual_hnode, *pos;
110 bucket = &hash_body->lchb_hash_tables[i];
111 spin_lock(&bucket->lhb_lock); /* lock the bucket */
112 hlist_for_each_safe(actual_hnode, pos, &(bucket->lhb_head)) {
113 lustre_hash_delitem_nolock(hash_body, i, actual_hnode);
115 spin_unlock(&bucket->lhb_lock);
118 /* free the hash_tables's memory space */
119 OBD_FREE(hash_body->lchb_hash_tables,
120 sizeof(*hash_body->lchb_hash_tables) *
121 hash_body->lchb_hash_max_size);
123 hash_body->lchb_hash_tables = NULL;
125 spin_unlock(&hash_body->lchb_lock);
128 /* free the hash_body's memory space */
129 if (hash_body != NULL) {
130 OBD_FREE(hash_body, sizeof(*hash_body));
131 *new_hash_body = NULL;
135 EXPORT_SYMBOL(lustre_hash_exit);
138 * only allow unique @key in hashtables, if the same @key has existed
139 * in hashtables, it will return with fails.
141 int lustre_hash_additem_unique(struct lustre_class_hash_body *hash_body,
142 void *key, struct hlist_node *actual_hnode)
145 struct lustre_hash_bucket *bucket = NULL;
146 struct lustre_hash_operations *hop = hash_body->lchb_hash_operations;
149 LASSERT(hlist_unhashed(actual_hnode));
150 hashent = hop->lustre_hashfn(hash_body, key);
152 /* get the hash-bucket and lock it */
153 bucket = &hash_body->lchb_hash_tables[hashent];
154 spin_lock(&bucket->lhb_lock);
156 if ( (lustre_hash_getitem_in_bucket_nolock(hash_body, hashent, key)) != NULL) {
157 /* the added-item exist in hashtables, so cannot add it again */
158 spin_unlock(&bucket->lhb_lock);
160 CWARN("Already found the key in hash [%s]\n",
161 hash_body->hashname);
165 hlist_add_head(actual_hnode, &(bucket->lhb_head));
167 #ifdef LUSTRE_HASH_DEBUG
168 /* hash distribute debug */
169 hash_body->lchb_hash_tables[hashent].lhb_item_count++;
170 CDEBUG(D_INFO, "hashname[%s] bucket[%d] has [%d] hashitem\n",
171 hash_body->hashname, hashent,
172 hash_body->lchb_hash_tables[hashent].lhb_item_count);
174 hop->lustre_hash_object_refcount_get(actual_hnode);
176 spin_unlock(&bucket->lhb_lock);
180 EXPORT_SYMBOL(lustre_hash_additem_unique);
183 * only allow unique @key in hashtables, if the same @key has existed
184 * in hashtables, it will return with fails.
186 void* lustre_hash_findadd_unique(struct lustre_class_hash_body *hash_body,
187 void *key, struct hlist_node *actual_hnode)
190 struct lustre_hash_bucket *bucket = NULL;
191 struct lustre_hash_operations *hop = hash_body->lchb_hash_operations;
192 struct hlist_node * hash_item_hnode = NULL;
196 LASSERT(hlist_unhashed(actual_hnode));
197 hashent = hop->lustre_hashfn(hash_body, key);
199 /* get the hash-bucket and lock it */
200 bucket = &hash_body->lchb_hash_tables[hashent];
201 spin_lock(&bucket->lhb_lock);
203 hash_item_hnode = lustre_hash_getitem_in_bucket_nolock(hash_body,
205 if ( hash_item_hnode != NULL) {
206 /* the added-item exist in hashtables, so cannot add it again */
207 obj = hop->lustre_hash_object_refcount_get(hash_item_hnode);
208 spin_unlock(&bucket->lhb_lock);
212 hlist_add_head(actual_hnode, &(bucket->lhb_head));
214 #ifdef LUSTRE_HASH_DEBUG
215 /* hash distribute debug */
216 hash_body->lchb_hash_tables[hashent].lhb_item_count++;
217 CDEBUG(D_INFO, "hashname[%s] bucket[%d] has [%d] hashitem\n",
218 hash_body->hashname, hashent,
219 hash_body->lchb_hash_tables[hashent].lhb_item_count);
221 obj = hop->lustre_hash_object_refcount_get(actual_hnode);
223 spin_unlock(&bucket->lhb_lock);
227 EXPORT_SYMBOL(lustre_hash_findadd_unique);
230 * this version of additem, it allow multi same @key <key, value> in hashtables.
231 * in this additem version, we don't need to check if exist same @key in hash
232 * tables, we only add it to related hashbucket.
233 * example: maybe same nid will be related to multi difference export
235 int lustre_hash_additem(struct lustre_class_hash_body *hash_body, void *key,
236 struct hlist_node *actual_hnode)
239 struct lustre_hash_bucket *bucket = NULL;
240 struct lustre_hash_operations *hop = hash_body->lchb_hash_operations;
243 LASSERT(hlist_unhashed(actual_hnode));
245 hashent = hop->lustre_hashfn(hash_body, key);
247 /* get the hashbucket and lock it */
248 bucket = &hash_body->lchb_hash_tables[hashent];
249 spin_lock(&bucket->lhb_lock);
251 hlist_add_head(actual_hnode, &(bucket->lhb_head));
253 #ifdef LUSTRE_HASH_DEBUG
254 /* hash distribute debug */
255 hash_body->lchb_hash_tables[hashent].lhb_item_count++;
256 CDEBUG(D_INFO, "hashname[%s] bucket[%d] has [%d] hashitem\n",
257 hash_body->hashname, hashent,
258 hash_body->lchb_hash_tables[hashent].lhb_item_count);
260 hop->lustre_hash_object_refcount_get(actual_hnode);
262 spin_unlock(&bucket->lhb_lock);
266 EXPORT_SYMBOL(lustre_hash_additem);
270 * this version of delitem will delete a hashitem with given @key,
271 * we need to search the <@key, @value> in hashbucket with @key,
272 * if match, the hashitem will be delete.
273 * we have a no-search version of delitem, it will directly delete a hashitem,
274 * doesn't need to search it in hashtables, so it is a O(1) delete.
276 int lustre_hash_delitem_by_key(struct lustre_class_hash_body *hash_body,
280 struct hlist_node * hash_item;
281 struct lustre_hash_bucket *bucket = NULL;
282 struct lustre_hash_operations *hop = hash_body->lchb_hash_operations;
286 hashent = hop->lustre_hashfn(hash_body, key);
288 /* first, lock the hashbucket */
289 bucket = &hash_body->lchb_hash_tables[hashent];
290 spin_lock(&bucket->lhb_lock);
292 /* get the hash_item from hash_bucket */
293 hash_item = lustre_hash_getitem_in_bucket_nolock(hash_body, hashent,
296 if (hash_item == NULL) {
297 spin_unlock(&bucket->lhb_lock);
301 /* call delitem_nolock() to delete the hash_item */
302 retval = lustre_hash_delitem_nolock(hash_body, hashent, hash_item);
304 spin_unlock(&bucket->lhb_lock);
308 EXPORT_SYMBOL(lustre_hash_delitem_by_key);
311 * the O(1) version of delete hash item,
312 * it will directly delete the hashitem with given @hash_item,
313 * the parameter @key used to get the relation hash bucket and lock it.
315 int lustre_hash_delitem(struct lustre_class_hash_body *hash_body,
316 void *key, struct hlist_node * hash_item)
320 struct lustre_hash_bucket *bucket = NULL;
321 struct lustre_hash_operations *hop = hash_body->lchb_hash_operations;
324 hashent = hop->lustre_hashfn(hash_body, key);
326 bucket = &hash_body->lchb_hash_tables[hashent];
327 spin_lock(&bucket->lhb_lock);
329 /* call delitem_nolock() to delete the hash_item */
330 retval = lustre_hash_delitem_nolock(hash_body, hashent, hash_item);
332 spin_unlock(&bucket->lhb_lock);
336 EXPORT_SYMBOL(lustre_hash_delitem);
338 void lustre_hash_bucket_iterate(struct lustre_class_hash_body *hash_body,
339 void *key, hash_item_iterate_cb func, void *data)
341 int hashent, find = 0;
342 struct lustre_hash_bucket *bucket = NULL;
343 struct hlist_node *hash_item_node = NULL;
344 struct lustre_hash_operations *hop = hash_body->lchb_hash_operations;
345 struct obd_export *tmp = NULL;
349 hashent = hop->lustre_hashfn(hash_body, key);
350 bucket = &hash_body->lchb_hash_tables[hashent];
352 spin_lock(&bucket->lhb_lock);
353 hlist_for_each(hash_item_node, &(bucket->lhb_head)) {
354 find = hop->lustre_hash_key_compare(key, hash_item_node);
356 tmp = hop->lustre_hash_object_refcount_get(hash_item_node);
358 hop->lustre_hash_object_refcount_put(hash_item_node);
361 spin_unlock(&bucket->lhb_lock);
363 EXPORT_SYMBOL(lustre_hash_bucket_iterate);
365 void lustre_hash_iterate_all(struct lustre_class_hash_body *hash_body,
366 hash_item_iterate_cb func, void *data)
369 struct lustre_hash_operations *hop = hash_body->lchb_hash_operations;
372 for( i = 0; i < hash_body->lchb_hash_max_size; i++ ) {
373 struct lustre_hash_bucket * bucket;
374 struct hlist_node * actual_hnode, *pos;
377 bucket = &hash_body->lchb_hash_tables[i];
378 #ifdef LUSTRE_HASH_DEBUG
379 CDEBUG(D_INFO, "idx %d - bucket %p\n", i, bucket);
381 spin_lock(&bucket->lhb_lock); /* lock the bucket */
382 hlist_for_each_safe(actual_hnode, pos, &(bucket->lhb_head)) {
383 obj = hop->lustre_hash_object_refcount_get(actual_hnode);
385 hop->lustre_hash_object_refcount_put(actual_hnode);
387 spin_unlock(&bucket->lhb_lock);
391 EXPORT_SYMBOL(lustre_hash_iterate_all);
394 void * lustre_hash_get_object_by_key(struct lustre_class_hash_body *hash_body,
398 struct hlist_node * hash_item_hnode = NULL;
399 void * obj_value = NULL;
400 struct lustre_hash_bucket *bucket = NULL;
401 struct lustre_hash_operations * hop = hash_body->lchb_hash_operations;
404 /* get the hash value from the given item */
405 hashent = hop->lustre_hashfn(hash_body, key);
407 bucket = &hash_body->lchb_hash_tables[hashent];
408 spin_lock(&bucket->lhb_lock); /* lock the bucket */
410 hash_item_hnode = lustre_hash_getitem_in_bucket_nolock(hash_body,
413 if (hash_item_hnode == NULL) {
414 spin_unlock(&bucket->lhb_lock); /* lock the bucket */
418 obj_value = hop->lustre_hash_object_refcount_get(hash_item_hnode);
419 spin_unlock(&bucket->lhb_lock); /* lock the bucket */
423 EXPORT_SYMBOL(lustre_hash_get_object_by_key);
425 /* string hashing using djb2 hash algorithm */
426 __u32 djb2_hashfn(struct lustre_class_hash_body *hash_body, void* key,
433 LASSERT(key != NULL);
435 for (i=0; i<size; i++)
436 hash = hash * 33 + ptr[i];
438 hash &= (hash_body->lchb_hash_max_size - 1);
444 * define (uuid <-> export) hash operations and function define
447 /* define the uuid hash operations */
448 struct lustre_hash_operations uuid_hash_operations = {
449 .lustre_hashfn = uuid_hashfn,
450 .lustre_hash_key_compare = uuid_hash_key_compare,
451 .lustre_hash_object_refcount_get = uuid_export_refcount_get,
452 .lustre_hash_object_refcount_put = uuid_export_refcount_put,
455 __u32 uuid_hashfn(struct lustre_class_hash_body *hash_body, void * key)
457 struct obd_uuid * uuid_key = key;
459 return djb2_hashfn(hash_body, uuid_key->uuid, sizeof(uuid_key->uuid));
462 /* Note, it is impossible to find an export that is in failed state with
464 int uuid_hash_key_compare(void *key, struct hlist_node *compared_hnode)
466 struct obd_export *export = NULL;
467 struct obd_uuid *uuid_key = NULL, *compared_uuid = NULL;
469 LASSERT( key != NULL);
471 uuid_key = (struct obd_uuid*)key;
473 export = hlist_entry(compared_hnode, struct obd_export, exp_uuid_hash);
475 compared_uuid = &export->exp_client_uuid;
477 RETURN(obd_uuid_equals(uuid_key, compared_uuid) &&
478 !export->exp_failed);
481 void * uuid_export_refcount_get(struct hlist_node * actual_hnode)
483 struct obd_export *export = NULL;
485 LASSERT(actual_hnode != NULL);
487 export = hlist_entry(actual_hnode, struct obd_export, exp_uuid_hash);
489 LASSERT(export != NULL);
491 class_export_get(export);
496 void uuid_export_refcount_put(struct hlist_node * actual_hnode)
498 struct obd_export *export = NULL;
500 LASSERT(actual_hnode != NULL);
502 export = hlist_entry(actual_hnode, struct obd_export, exp_uuid_hash);
504 LASSERT(export != NULL);
506 class_export_put(export);
510 * define (nid <-> export) hash operations and function define
513 /* define the nid hash operations */
514 struct lustre_hash_operations nid_hash_operations = {
515 .lustre_hashfn = nid_hashfn,
516 .lustre_hash_key_compare = nid_hash_key_compare,
517 .lustre_hash_object_refcount_get = nid_export_refcount_get,
518 .lustre_hash_object_refcount_put = nid_export_refcount_put,
521 __u32 nid_hashfn(struct lustre_class_hash_body *hash_body, void * key)
523 return djb2_hashfn(hash_body, key, sizeof(lnet_nid_t));
526 /* Note, it is impossible to find an export that is in failed state with
528 int nid_hash_key_compare(void *key, struct hlist_node *compared_hnode)
530 struct obd_export *export = NULL;
531 lnet_nid_t *nid_key = NULL;
533 LASSERT( key != NULL);
535 nid_key = (lnet_nid_t*)key;
537 export = hlist_entry(compared_hnode, struct obd_export, exp_nid_hash);
539 return (export->exp_connection->c_peer.nid == *nid_key &&
540 !export->exp_failed);
543 void *nid_export_refcount_get(struct hlist_node *actual_hnode)
545 struct obd_export *export = NULL;
547 LASSERT(actual_hnode != NULL);
549 export = hlist_entry(actual_hnode, struct obd_export, exp_nid_hash);
551 LASSERT(export != NULL);
553 class_export_get(export);
558 void nid_export_refcount_put(struct hlist_node *actual_hnode)
560 struct obd_export *export = NULL;
562 LASSERT(actual_hnode != NULL);
564 export = hlist_entry(actual_hnode, struct obd_export, exp_nid_hash);
566 LASSERT(export != NULL);
568 class_export_put(export);
572 * define (net_peer <-> connection) hash operations and function define
575 /* define the conn hash operations */
576 struct lustre_hash_operations conn_hash_operations = {
577 .lustre_hashfn = conn_hashfn,
578 .lustre_hash_key_compare = conn_hash_key_compare,
579 .lustre_hash_object_refcount_get = conn_refcount_get,
580 .lustre_hash_object_refcount_put = conn_refcount_put,
582 EXPORT_SYMBOL(conn_hash_operations);
584 __u32 conn_hashfn(struct lustre_class_hash_body *hash_body, void * key)
586 return djb2_hashfn(hash_body, key, sizeof(lnet_process_id_t));
589 int conn_hash_key_compare(void *key, struct hlist_node *compared_hnode)
591 struct ptlrpc_connection *c = NULL;
592 lnet_process_id_t *conn_key = NULL;
594 LASSERT( key != NULL);
596 conn_key = (lnet_process_id_t*)key;
598 c = hlist_entry(compared_hnode, struct ptlrpc_connection, c_hash);
600 return (conn_key->nid == c->c_peer.nid &&
601 conn_key->pid == c->c_peer.pid);
604 void *conn_refcount_get(struct hlist_node *actual_hnode)
606 struct ptlrpc_connection *c = NULL;
608 LASSERT(actual_hnode != NULL);
610 c = hlist_entry(actual_hnode, struct ptlrpc_connection, c_hash);
614 atomic_inc(&c->c_refcount);
619 void conn_refcount_put(struct hlist_node *actual_hnode)
621 struct ptlrpc_connection *c = NULL;
623 LASSERT(actual_hnode != NULL);
625 c = hlist_entry(actual_hnode, struct ptlrpc_connection, c_hash);
629 atomic_dec(&c->c_refcount);
632 /*******************************************************************************/
633 /* ( nid<>nidstats ) hash operations define */
635 struct lustre_hash_operations nid_stat_hash_operations = {
636 .lustre_hashfn = nid_hashfn,
637 .lustre_hash_key_compare = nidstats_hash_key_compare,
638 .lustre_hash_object_refcount_get = nidstats_refcount_get,
639 .lustre_hash_object_refcount_put = nidstats_refcount_put,
641 EXPORT_SYMBOL(nid_stat_hash_operations);
643 int nidstats_hash_key_compare(void *key, struct hlist_node * compared_hnode)
645 struct nid_stat *data;
648 LASSERT( key != NULL);
650 nid_key = (lnet_nid_t*)key;
651 data = hlist_entry(compared_hnode, struct nid_stat, nid_hash);
653 return (data->nid == *nid_key);
656 void* nidstats_refcount_get(struct hlist_node * actual_hnode)
658 struct nid_stat *data;
660 data = hlist_entry(actual_hnode, struct nid_stat, nid_hash);
661 data->nid_exp_ref_count++;
666 void nidstats_refcount_put(struct hlist_node * actual_hnode)
668 struct nid_stat *data;
670 data = hlist_entry(actual_hnode, struct nid_stat, nid_hash);
671 data->nid_exp_ref_count--;
675 /*******************************************************************************/
679 * define ( lqs <-> qctxt ) hash operations and function define
682 /* define the conn hash operations */
683 struct lustre_hash_operations lqs_hash_operations = {
684 .lustre_hashfn = lqs_hashfn,
685 .lustre_hash_key_compare = lqs_hash_key_compare,
686 .lustre_hash_object_refcount_get = lqs_refcount_get,
687 .lustre_hash_object_refcount_put = lqs_refcount_put,
689 EXPORT_SYMBOL(lqs_hash_operations);
691 /* string hashing using djb2 hash algorithm */
692 __u32 lqs_hashfn(struct lustre_class_hash_body *hash_body, void * key)
694 struct quota_adjust_qunit *lqs_key = NULL;
697 LASSERT(key != NULL);
699 lqs_key = (struct quota_adjust_qunit *)key;
701 hash = QAQ_IS_GRP(lqs_key) ? 5381 : 5387;
702 hash *= lqs_key->qaq_id;
704 hash &= (hash_body->lchb_hash_max_size - 1);
709 int lqs_hash_key_compare(void *key, struct hlist_node *compared_hnode)
711 struct quota_adjust_qunit *lqs_key = NULL;
712 struct lustre_qunit_size *q = NULL;
715 LASSERT( key != NULL);
717 lqs_key = (struct quota_adjust_qunit *)key;
719 q = hlist_entry(compared_hnode, struct lustre_qunit_size, lqs_hash);
721 spin_lock(&q->lqs_lock);
722 if (lqs_key->qaq_id == q->lqs_id && QAQ_IS_GRP(lqs_key) == LQS_IS_GRP(q))
724 spin_unlock(&q->lqs_lock);
729 void * lqs_refcount_get(struct hlist_node * actual_hnode)
731 struct lustre_qunit_size *q = NULL;
733 LASSERT(actual_hnode != NULL);
735 q = hlist_entry(actual_hnode, struct lustre_qunit_size, lqs_hash);
744 void lqs_refcount_put(struct hlist_node * actual_hnode)
746 struct lustre_qunit_size *q = NULL;
748 LASSERT(actual_hnode != NULL);
750 q = hlist_entry(actual_hnode, struct lustre_qunit_size, lqs_hash);