Whamcloud - gitweb
b=10600
[fs/lustre-release.git] / lustre / obdclass / class_hash.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (C) 2005 Cluster File Systems, Inc.
5  *   Author: YuZhangyong <yzy@clusterfs.com>
6  *
7  *   This file is part of Lustre, http://www.lustre.org/
8  *
9  *   No redistribution or use is permitted outside of Cluster File Systems, Inc.
10  *
11  *   Implement a hash class for hash process in lustre system.
12  */
13
14 #ifndef __KERNEL__
15 #include <liblustre.h>
16 #include <obd.h>
17 #endif
18
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>
25
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)
29 {
30         int i, n = 0;
31         struct lustre_class_hash_body *hash_body = NULL;
32
33         LASSERT(hashsize > 0);
34         LASSERT(hash_operations != NULL);
35         ENTRY;
36
37         i = hashsize;
38         while (i != 0) {
39                 if (i & 0x1)
40                         n++;
41                 i >>= 1;
42         }
43
44         LASSERTF(n == 1, "hashsize %u isn't 2^n\n", hashsize);
45
46         /* alloc space for hash_body */
47         OBD_ALLOC(hash_body, sizeof(*hash_body));
48
49         if (hash_body == NULL) {
50                 CERROR("Cannot alloc space for hash body, hashname = %s \n",
51                         hashname);
52                 RETURN(-ENOMEM);
53         }
54
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;
60
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);
64
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",
68                         hash_body->hashname);
69                 RETURN(-ENOMEM);
70         }
71
72         spin_lock_init(&hash_body->lchb_lock); /* initialize the body lock */
73
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);
78         }
79         *hash_body_new = hash_body;
80
81         RETURN(0);
82 }
83 EXPORT_SYMBOL(lustre_hash_init);
84
85 void lustre_hash_exit(struct lustre_class_hash_body **new_hash_body)
86 {
87         int i;
88         struct lustre_class_hash_body *hash_body = NULL;
89         ENTRY;
90
91         hash_body = *new_hash_body;
92
93         if (hash_body == NULL) {
94                 CWARN("hash body has been deleted\n");
95                 goto out_hash;
96         }
97
98         spin_lock(&hash_body->lchb_lock); /* lock the hash tables */
99
100         if (hash_body->lchb_hash_tables == NULL ) {
101                 spin_unlock(&hash_body->lchb_lock);
102                 CWARN("hash tables has been deleted\n");
103                 goto out_hash;
104         }
105
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;
109
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);
114                 }
115                 spin_unlock(&bucket->lhb_lock);
116         }
117
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);
122
123         hash_body->lchb_hash_tables = NULL;
124
125         spin_unlock(&hash_body->lchb_lock);
126
127 out_hash : 
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;
132         }
133         EXIT;
134 }
135 EXPORT_SYMBOL(lustre_hash_exit);
136
137 /*
138  * only allow unique @key in hashtables, if the same @key has existed 
139  * in hashtables, it will return with fails.
140  */
141 int lustre_hash_additem_unique(struct lustre_class_hash_body *hash_body, 
142                                void *key, struct hlist_node *actual_hnode)
143 {
144         int hashent;
145         struct lustre_hash_bucket *bucket = NULL;
146         struct lustre_hash_operations *hop = hash_body->lchb_hash_operations;
147         ENTRY;
148
149         LASSERT(hlist_unhashed(actual_hnode));
150         hashent = hop->lustre_hashfn(hash_body, key);
151
152         /* get the hash-bucket and lock it */
153         bucket = &hash_body->lchb_hash_tables[hashent];
154         spin_lock(&bucket->lhb_lock);
155
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);
159
160                 CWARN("Already found the key in hash [%s]\n", 
161                       hash_body->hashname);
162                 RETURN(-EALREADY);
163         }
164
165         hlist_add_head(actual_hnode, &(bucket->lhb_head));
166
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);
173 #endif  
174         hop->lustre_hash_object_refcount_get(actual_hnode); 
175
176         spin_unlock(&bucket->lhb_lock);
177
178         RETURN(0);
179 }
180 EXPORT_SYMBOL(lustre_hash_additem_unique);
181
182 /*
183  * only allow unique @key in hashtables, if the same @key has existed 
184  * in hashtables, it will return with fails.
185  */
186 void* lustre_hash_findadd_unique(struct lustre_class_hash_body *hash_body, 
187                                      void *key, struct hlist_node *actual_hnode)
188 {
189         int hashent;
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;
193         void *obj;
194         ENTRY;
195
196         LASSERT(hlist_unhashed(actual_hnode));
197         hashent = hop->lustre_hashfn(hash_body, key);
198
199         /* get the hash-bucket and lock it */
200         bucket = &hash_body->lchb_hash_tables[hashent];
201         spin_lock(&bucket->lhb_lock);
202
203         hash_item_hnode = lustre_hash_getitem_in_bucket_nolock(hash_body,
204                                                                hashent, key);
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);
209                 RETURN(obj);
210         }
211
212         hlist_add_head(actual_hnode, &(bucket->lhb_head));
213
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);
220 #endif
221         obj = hop->lustre_hash_object_refcount_get(actual_hnode);
222
223         spin_unlock(&bucket->lhb_lock);
224
225         RETURN(obj);
226 }
227 EXPORT_SYMBOL(lustre_hash_findadd_unique);
228
229 /*
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
234  */
235 int lustre_hash_additem(struct lustre_class_hash_body *hash_body, void *key, 
236                          struct hlist_node *actual_hnode)
237 {
238         int hashent;
239         struct lustre_hash_bucket *bucket = NULL;
240         struct lustre_hash_operations *hop = hash_body->lchb_hash_operations;
241         ENTRY;
242
243         LASSERT(hlist_unhashed(actual_hnode));
244
245         hashent = hop->lustre_hashfn(hash_body, key);
246
247         /* get the hashbucket and lock it */
248         bucket = &hash_body->lchb_hash_tables[hashent];
249         spin_lock(&bucket->lhb_lock);
250
251         hlist_add_head(actual_hnode, &(bucket->lhb_head));
252
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);
259 #endif  
260         hop->lustre_hash_object_refcount_get(actual_hnode); 
261
262         spin_unlock(&bucket->lhb_lock);
263
264         RETURN(0);
265 }
266 EXPORT_SYMBOL(lustre_hash_additem);
267
268
269 /*
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.
275  */
276 int lustre_hash_delitem_by_key(struct lustre_class_hash_body *hash_body, 
277                                void *key)
278 {
279         int hashent ;
280         struct hlist_node * hash_item;
281         struct lustre_hash_bucket *bucket = NULL;
282         struct lustre_hash_operations *hop = hash_body->lchb_hash_operations;
283         int retval = 0;
284         ENTRY;
285
286         hashent = hop->lustre_hashfn(hash_body, key);
287
288         /* first, lock the hashbucket */
289         bucket = &hash_body->lchb_hash_tables[hashent];
290         spin_lock(&bucket->lhb_lock);
291
292         /* get the hash_item from hash_bucket */
293         hash_item = lustre_hash_getitem_in_bucket_nolock(hash_body, hashent, 
294                                                          key);
295
296         if (hash_item == NULL) {
297                 spin_unlock(&bucket->lhb_lock);
298                 RETURN(-ENOENT);
299         }
300
301         /* call delitem_nolock() to delete the hash_item */
302         retval = lustre_hash_delitem_nolock(hash_body, hashent, hash_item);
303
304         spin_unlock(&bucket->lhb_lock);
305
306         RETURN(retval);
307 }
308 EXPORT_SYMBOL(lustre_hash_delitem_by_key);
309
310 /*
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.
314  */
315 int lustre_hash_delitem(struct lustre_class_hash_body *hash_body, 
316                         void *key, struct hlist_node * hash_item)
317 {  
318         int hashent = 0;
319         int retval = 0;
320         struct lustre_hash_bucket *bucket = NULL;
321         struct lustre_hash_operations *hop = hash_body->lchb_hash_operations;
322         ENTRY;
323
324         hashent = hop->lustre_hashfn(hash_body, key);
325
326         bucket = &hash_body->lchb_hash_tables[hashent];
327         spin_lock(&bucket->lhb_lock);
328
329         /* call delitem_nolock() to delete the hash_item */
330         retval = lustre_hash_delitem_nolock(hash_body, hashent, hash_item);
331
332         spin_unlock(&bucket->lhb_lock);
333
334         RETURN(retval);
335 }
336 EXPORT_SYMBOL(lustre_hash_delitem);
337
338 void lustre_hash_bucket_iterate(struct lustre_class_hash_body *hash_body,
339                                 void *key, hash_item_iterate_cb func, void *data)
340 {
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;
346
347         ENTRY;
348
349         hashent = hop->lustre_hashfn(hash_body, key);
350         bucket = &hash_body->lchb_hash_tables[hashent];
351
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);
355                 if (find) {
356                         tmp = hop->lustre_hash_object_refcount_get(hash_item_node);
357                         func(tmp, data);
358                         hop->lustre_hash_object_refcount_put(hash_item_node);
359                 }
360         }
361         spin_unlock(&bucket->lhb_lock);
362 }
363 EXPORT_SYMBOL(lustre_hash_bucket_iterate);
364
365 void lustre_hash_iterate_all(struct lustre_class_hash_body *hash_body,
366                             hash_item_iterate_cb func, void *data)
367 {
368         int i;
369         struct lustre_hash_operations *hop = hash_body->lchb_hash_operations;
370         ENTRY;
371
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;
375                 void *obj;
376
377                 bucket = &hash_body->lchb_hash_tables[i];
378 #ifdef LUSTRE_HASH_DEBUG
379                 CDEBUG(D_INFO, "idx %d - bucket %p\n", i, bucket);
380 #endif
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);
384                         func(obj, data);
385                         hop->lustre_hash_object_refcount_put(actual_hnode);
386                 }
387                 spin_unlock(&bucket->lhb_lock);
388         }
389         EXIT;
390 }
391 EXPORT_SYMBOL(lustre_hash_iterate_all);
392
393
394 void * lustre_hash_get_object_by_key(struct lustre_class_hash_body *hash_body,
395                                      void *key)
396 {
397         int hashent ;
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;
402         ENTRY;
403
404         /* get the hash value from the given item */
405         hashent = hop->lustre_hashfn(hash_body, key);
406
407         bucket = &hash_body->lchb_hash_tables[hashent];
408         spin_lock(&bucket->lhb_lock); /* lock the bucket */
409
410         hash_item_hnode = lustre_hash_getitem_in_bucket_nolock(hash_body, 
411                                                                hashent, key);
412
413         if (hash_item_hnode == NULL) {
414                 spin_unlock(&bucket->lhb_lock); /* lock the bucket */
415                 RETURN(NULL);
416         }
417
418         obj_value = hop->lustre_hash_object_refcount_get(hash_item_hnode);
419         spin_unlock(&bucket->lhb_lock); /* lock the bucket */
420
421         RETURN(obj_value);
422 }
423 EXPORT_SYMBOL(lustre_hash_get_object_by_key);
424
425 /* string hashing using djb2 hash algorithm */
426 __u32 djb2_hashfn(struct lustre_class_hash_body *hash_body,  void* key, 
427                   size_t size)
428 {
429         __u32 hash = 5381;
430         int i;
431         char *ptr = key;
432
433         LASSERT(key != NULL);
434
435         for (i=0; i<size; i++) 
436                 hash = hash * 33 + ptr[i];
437
438         hash &= (hash_body->lchb_hash_max_size - 1);
439
440         RETURN(hash);
441 }
442
443 /*
444  * define (uuid <-> export) hash operations and function define
445  */
446
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,
453 };
454
455 __u32 uuid_hashfn(struct lustre_class_hash_body *hash_body,  void * key)
456 {
457         struct obd_uuid * uuid_key = key;
458
459         return djb2_hashfn(hash_body, uuid_key->uuid, sizeof(uuid_key->uuid));
460 }
461
462 /* Note, it is impossible to find an export that is in failed state with
463  * this function */
464 int uuid_hash_key_compare(void *key, struct hlist_node *compared_hnode)
465 {
466         struct obd_export *export = NULL;
467         struct obd_uuid *uuid_key = NULL, *compared_uuid = NULL;
468
469         LASSERT( key != NULL);
470
471         uuid_key = (struct obd_uuid*)key;
472
473         export = hlist_entry(compared_hnode, struct obd_export, exp_uuid_hash);
474
475         compared_uuid = &export->exp_client_uuid;
476
477         RETURN(obd_uuid_equals(uuid_key, compared_uuid) &&
478                !export->exp_failed);
479 }
480
481 void * uuid_export_refcount_get(struct hlist_node * actual_hnode)
482 {
483         struct obd_export *export = NULL;
484
485         LASSERT(actual_hnode != NULL);
486
487         export = hlist_entry(actual_hnode, struct obd_export, exp_uuid_hash);
488
489         LASSERT(export != NULL);
490
491         class_export_get(export);
492
493         RETURN(export);
494 }
495
496 void uuid_export_refcount_put(struct hlist_node * actual_hnode)
497 {
498         struct obd_export *export = NULL;
499
500         LASSERT(actual_hnode != NULL);
501
502         export = hlist_entry(actual_hnode, struct obd_export, exp_uuid_hash);
503
504         LASSERT(export != NULL);
505
506         class_export_put(export);
507 }
508
509 /*
510  * define (nid <-> export) hash operations and function define
511  */
512
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,
519 };
520
521 __u32 nid_hashfn(struct lustre_class_hash_body *hash_body,  void * key)
522 {
523         return djb2_hashfn(hash_body, key, sizeof(lnet_nid_t));
524 }
525
526 /* Note, it is impossible to find an export that is in failed state with
527  * this function */
528 int nid_hash_key_compare(void *key, struct hlist_node *compared_hnode)
529 {
530         struct obd_export *export = NULL;
531         lnet_nid_t *nid_key = NULL;
532
533         LASSERT( key != NULL);
534
535         nid_key = (lnet_nid_t*)key;
536
537         export = hlist_entry(compared_hnode, struct obd_export, exp_nid_hash);
538
539         return (export->exp_connection->c_peer.nid == *nid_key &&
540                 !export->exp_failed);
541 }
542
543 void *nid_export_refcount_get(struct hlist_node *actual_hnode)
544 {
545         struct obd_export *export = NULL;
546
547         LASSERT(actual_hnode != NULL);
548
549         export = hlist_entry(actual_hnode, struct obd_export, exp_nid_hash);
550
551         LASSERT(export != NULL);
552
553         class_export_get(export);
554
555         RETURN(export);
556 }
557
558 void nid_export_refcount_put(struct hlist_node *actual_hnode)
559 {
560         struct obd_export *export = NULL;
561
562         LASSERT(actual_hnode != NULL);
563
564         export = hlist_entry(actual_hnode, struct obd_export, exp_nid_hash);
565
566         LASSERT(export != NULL);
567
568         class_export_put(export);
569 }
570
571 /*
572  * define (net_peer <-> connection) hash operations and function define
573  */
574
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,
581 };
582 EXPORT_SYMBOL(conn_hash_operations);
583
584 __u32 conn_hashfn(struct lustre_class_hash_body *hash_body,  void * key)
585 {
586         return djb2_hashfn(hash_body, key, sizeof(lnet_process_id_t));
587 }
588
589 int conn_hash_key_compare(void *key, struct hlist_node *compared_hnode)
590 {
591         struct ptlrpc_connection *c = NULL;
592         lnet_process_id_t *conn_key = NULL;
593
594         LASSERT( key != NULL);
595
596         conn_key = (lnet_process_id_t*)key;
597
598         c = hlist_entry(compared_hnode, struct ptlrpc_connection, c_hash);
599
600         return (conn_key->nid == c->c_peer.nid &&
601                 conn_key->pid == c->c_peer.pid);
602 }
603
604 void *conn_refcount_get(struct hlist_node *actual_hnode)
605 {
606         struct ptlrpc_connection *c = NULL;
607
608         LASSERT(actual_hnode != NULL);
609
610         c = hlist_entry(actual_hnode, struct ptlrpc_connection, c_hash);
611
612         LASSERT(c != NULL);
613
614         atomic_inc(&c->c_refcount);
615
616         RETURN(c);
617 }
618
619 void conn_refcount_put(struct hlist_node *actual_hnode)
620 {
621         struct ptlrpc_connection *c = NULL;
622
623         LASSERT(actual_hnode != NULL);
624
625         c = hlist_entry(actual_hnode, struct ptlrpc_connection, c_hash);
626
627         LASSERT(c != NULL);
628
629         atomic_dec(&c->c_refcount);
630 }
631
632 /*******************************************************************************/
633 /* ( nid<>nidstats ) hash operations define */
634
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,
640 };
641 EXPORT_SYMBOL(nid_stat_hash_operations);
642
643 int nidstats_hash_key_compare(void *key, struct hlist_node * compared_hnode)
644 {
645         struct nid_stat *data;
646         lnet_nid_t *nid_key;
647
648         LASSERT( key != NULL);
649
650         nid_key = (lnet_nid_t*)key;
651         data = hlist_entry(compared_hnode, struct nid_stat, nid_hash);
652
653         return (data->nid == *nid_key);
654 }
655
656 void* nidstats_refcount_get(struct hlist_node * actual_hnode)
657 {
658         struct nid_stat *data;
659
660         data = hlist_entry(actual_hnode, struct nid_stat, nid_hash);
661         data->nid_exp_ref_count++;
662
663         RETURN(data);
664 }
665
666 void nidstats_refcount_put(struct hlist_node * actual_hnode)
667 {
668         struct nid_stat *data;
669
670         data = hlist_entry(actual_hnode, struct nid_stat, nid_hash);
671         data->nid_exp_ref_count--;
672
673 }
674
675 /*******************************************************************************/
676
677 #ifdef __KERNEL__
678 /*
679  * define ( lqs <-> qctxt ) hash operations and function define
680  */
681
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,
688 };
689 EXPORT_SYMBOL(lqs_hash_operations);
690
691 /* string hashing using djb2 hash algorithm */
692 __u32 lqs_hashfn(struct lustre_class_hash_body *hash_body,  void * key)
693 {
694         struct quota_adjust_qunit *lqs_key = NULL;
695         __u32 hash;
696
697         LASSERT(key != NULL);
698
699         lqs_key = (struct quota_adjust_qunit *)key;
700
701         hash = QAQ_IS_GRP(lqs_key) ? 5381 : 5387;
702         hash *= lqs_key->qaq_id;
703
704         hash &= (hash_body->lchb_hash_max_size - 1);
705
706         RETURN(hash);
707 }
708
709 int lqs_hash_key_compare(void *key, struct hlist_node *compared_hnode)
710 {
711         struct quota_adjust_qunit *lqs_key = NULL;
712         struct lustre_qunit_size *q = NULL;
713         int retval = 0;
714
715         LASSERT( key != NULL);
716
717         lqs_key = (struct quota_adjust_qunit *)key;
718
719         q = hlist_entry(compared_hnode, struct lustre_qunit_size, lqs_hash);
720
721         spin_lock(&q->lqs_lock);
722         if (lqs_key->qaq_id == q->lqs_id && QAQ_IS_GRP(lqs_key) == LQS_IS_GRP(q))
723                  retval = 1;
724         spin_unlock(&q->lqs_lock);
725
726         return retval;
727 }
728
729 void * lqs_refcount_get(struct hlist_node * actual_hnode)
730 {
731         struct lustre_qunit_size *q = NULL;
732
733         LASSERT(actual_hnode != NULL);
734
735         q = hlist_entry(actual_hnode, struct lustre_qunit_size, lqs_hash);
736
737         LASSERT(q != NULL);
738
739         lqs_getref(q);
740
741         RETURN(q);
742 }
743
744 void lqs_refcount_put(struct hlist_node * actual_hnode)
745 {
746         struct lustre_qunit_size *q = NULL;
747
748         LASSERT(actual_hnode != NULL);
749
750         q = hlist_entry(actual_hnode, struct lustre_qunit_size, lqs_hash);
751
752         LASSERT(q != NULL);
753
754         lqs_putref(q);
755 }
756 #endif