xref: /onnv-gate/usr/src/uts/common/avs/ns/sdbc/sd_hash.c (revision 7836:4e95154b5b7a)
1*7836SJohn.Forte@Sun.COM /*
2*7836SJohn.Forte@Sun.COM  * CDDL HEADER START
3*7836SJohn.Forte@Sun.COM  *
4*7836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
5*7836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
6*7836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
7*7836SJohn.Forte@Sun.COM  *
8*7836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*7836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*7836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
11*7836SJohn.Forte@Sun.COM  * and limitations under the License.
12*7836SJohn.Forte@Sun.COM  *
13*7836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*7836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*7836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*7836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*7836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*7836SJohn.Forte@Sun.COM  *
19*7836SJohn.Forte@Sun.COM  * CDDL HEADER END
20*7836SJohn.Forte@Sun.COM  */
21*7836SJohn.Forte@Sun.COM /*
22*7836SJohn.Forte@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*7836SJohn.Forte@Sun.COM  * Use is subject to license terms.
24*7836SJohn.Forte@Sun.COM  */
25*7836SJohn.Forte@Sun.COM 
26*7836SJohn.Forte@Sun.COM #include <sys/types.h>
27*7836SJohn.Forte@Sun.COM #include <sys/ksynch.h>
28*7836SJohn.Forte@Sun.COM #include <sys/cmn_err.h>
29*7836SJohn.Forte@Sun.COM #include <sys/kmem.h>
30*7836SJohn.Forte@Sun.COM #include <sys/ddi.h>
31*7836SJohn.Forte@Sun.COM #include <sys/nsc_thread.h>
32*7836SJohn.Forte@Sun.COM #include <sys/nsctl/nsctl.h>
33*7836SJohn.Forte@Sun.COM 
34*7836SJohn.Forte@Sun.COM #include <sys/sdt.h>		/* dtrace is S10 or later */
35*7836SJohn.Forte@Sun.COM 
36*7836SJohn.Forte@Sun.COM #include "sd_bcache.h"
37*7836SJohn.Forte@Sun.COM #include "sd_hash.h"
38*7836SJohn.Forte@Sun.COM 
39*7836SJohn.Forte@Sun.COM #if defined(_SD_DEBUG)
40*7836SJohn.Forte@Sun.COM int _sd_hash_max_inlist = 0;
41*7836SJohn.Forte@Sun.COM #endif
42*7836SJohn.Forte@Sun.COM 
43*7836SJohn.Forte@Sun.COM 
44*7836SJohn.Forte@Sun.COM #define	_SD_HB_LOCKS 32
45*7836SJohn.Forte@Sun.COM static kmutex_t _sd_hb_locks[_SD_HB_LOCKS];
46*7836SJohn.Forte@Sun.COM 
47*7836SJohn.Forte@Sun.COM 
48*7836SJohn.Forte@Sun.COM /*
49*7836SJohn.Forte@Sun.COM  * _sdbc_hash_load - allocate all the locks for buckets.
50*7836SJohn.Forte@Sun.COM  *
51*7836SJohn.Forte@Sun.COM  *
52*7836SJohn.Forte@Sun.COM  */
53*7836SJohn.Forte@Sun.COM int
_sdbc_hash_load(void)54*7836SJohn.Forte@Sun.COM _sdbc_hash_load(void)
55*7836SJohn.Forte@Sun.COM {
56*7836SJohn.Forte@Sun.COM 	int i;
57*7836SJohn.Forte@Sun.COM 	for (i = 0; i < _SD_HB_LOCKS; i++) {
58*7836SJohn.Forte@Sun.COM 		mutex_init(&_sd_hb_locks[i], NULL, MUTEX_DRIVER, NULL);
59*7836SJohn.Forte@Sun.COM 	}
60*7836SJohn.Forte@Sun.COM 	return (0);
61*7836SJohn.Forte@Sun.COM }
62*7836SJohn.Forte@Sun.COM 
63*7836SJohn.Forte@Sun.COM /*
64*7836SJohn.Forte@Sun.COM  * _sdbc_hash_unload - free all the locks for buckets.
65*7836SJohn.Forte@Sun.COM  *
66*7836SJohn.Forte@Sun.COM  *
67*7836SJohn.Forte@Sun.COM  */
68*7836SJohn.Forte@Sun.COM void
_sdbc_hash_unload(void)69*7836SJohn.Forte@Sun.COM _sdbc_hash_unload(void)
70*7836SJohn.Forte@Sun.COM {
71*7836SJohn.Forte@Sun.COM 	int i;
72*7836SJohn.Forte@Sun.COM 	for (i = 0; i < _SD_HB_LOCKS; i++) {
73*7836SJohn.Forte@Sun.COM 		mutex_destroy(&_sd_hb_locks[i]);
74*7836SJohn.Forte@Sun.COM 	}
75*7836SJohn.Forte@Sun.COM }
76*7836SJohn.Forte@Sun.COM 
77*7836SJohn.Forte@Sun.COM 
78*7836SJohn.Forte@Sun.COM /*
79*7836SJohn.Forte@Sun.COM  * _sdbc_hash_configure - create a hash table
80*7836SJohn.Forte@Sun.COM  *
81*7836SJohn.Forte@Sun.COM  * ARGUMENTS:
82*7836SJohn.Forte@Sun.COM  *	num_ents - Number of entries (or hash buckets)
83*7836SJohn.Forte@Sun.COM  *	htype    - Type of memory to allocate.
84*7836SJohn.Forte@Sun.COM  *
85*7836SJohn.Forte@Sun.COM  * RETURNS:
86*7836SJohn.Forte@Sun.COM  *	The address of the hash table just created
87*7836SJohn.Forte@Sun.COM  *	or zero in the event of failure.
88*7836SJohn.Forte@Sun.COM  *
89*7836SJohn.Forte@Sun.COM  * USAGE:
90*7836SJohn.Forte@Sun.COM  *	This routine rounds of the number of entries to the next higher
91*7836SJohn.Forte@Sun.COM  *	power of 2. Allocate the hash buckets and initializes the locks
92*7836SJohn.Forte@Sun.COM  *	and returns the hash table that is created.
93*7836SJohn.Forte@Sun.COM  *	It is the caller's responsibility to save the hash_table and pass
94*7836SJohn.Forte@Sun.COM  *	it as a key for future accesses to the hash.
95*7836SJohn.Forte@Sun.COM  *	It is also the caller's responsibility to destroy the hash table
96*7836SJohn.Forte@Sun.COM  *	when appropriate.
97*7836SJohn.Forte@Sun.COM  */
98*7836SJohn.Forte@Sun.COM 
99*7836SJohn.Forte@Sun.COM 
100*7836SJohn.Forte@Sun.COM _sd_hash_table_t *
_sdbc_hash_configure(int num_ents)101*7836SJohn.Forte@Sun.COM _sdbc_hash_configure(int num_ents)
102*7836SJohn.Forte@Sun.COM {
103*7836SJohn.Forte@Sun.COM 	_sd_hash_table_t *hash_table;
104*7836SJohn.Forte@Sun.COM 	_sd_hash_bucket_t *bucket;
105*7836SJohn.Forte@Sun.COM 	int i;
106*7836SJohn.Forte@Sun.COM 	int get_high_bit(int);
107*7836SJohn.Forte@Sun.COM 
108*7836SJohn.Forte@Sun.COM 	if ((hash_table = (_sd_hash_table_t *)
109*7836SJohn.Forte@Sun.COM 		nsc_kmem_zalloc(sizeof (_sd_hash_table_t),
110*7836SJohn.Forte@Sun.COM 				KM_SLEEP, sdbc_hash_mem)) == NULL)
111*7836SJohn.Forte@Sun.COM 		return (NULL);
112*7836SJohn.Forte@Sun.COM 
113*7836SJohn.Forte@Sun.COM 	hash_table->ht_bits = get_high_bit(num_ents);
114*7836SJohn.Forte@Sun.COM 	hash_table->ht_size = (1 << hash_table->ht_bits);
115*7836SJohn.Forte@Sun.COM 
116*7836SJohn.Forte@Sun.COM 	/*
117*7836SJohn.Forte@Sun.COM 	 * this is where we compute the mask used in the hash function
118*7836SJohn.Forte@Sun.COM 	 * the ht_nmask is basically an not of ht_mask used in hash
119*7836SJohn.Forte@Sun.COM 	 * function.
120*7836SJohn.Forte@Sun.COM 	 */
121*7836SJohn.Forte@Sun.COM 	hash_table->ht_mask = (hash_table->ht_size - 1);
122*7836SJohn.Forte@Sun.COM 	hash_table->ht_nmask = (~0 & ~(hash_table->ht_mask));
123*7836SJohn.Forte@Sun.COM 
124*7836SJohn.Forte@Sun.COM 	if ((hash_table->ht_buckets = (_sd_hash_bucket_t *)
125*7836SJohn.Forte@Sun.COM 		nsc_kmem_zalloc(hash_table->ht_size *
126*7836SJohn.Forte@Sun.COM 				sizeof (_sd_hash_bucket_t), KM_SLEEP,
127*7836SJohn.Forte@Sun.COM 				sdbc_hash_mem)) == NULL)
128*7836SJohn.Forte@Sun.COM 		return (NULL);
129*7836SJohn.Forte@Sun.COM 
130*7836SJohn.Forte@Sun.COM 	for (i = 0; i < (hash_table->ht_size); i++) {
131*7836SJohn.Forte@Sun.COM 		bucket = (hash_table->ht_buckets + i);
132*7836SJohn.Forte@Sun.COM 
133*7836SJohn.Forte@Sun.COM 		bucket->hb_lock = &_sd_hb_locks[i % _SD_HB_LOCKS];
134*7836SJohn.Forte@Sun.COM 		bucket->hb_head = bucket->hb_tail = NULL;
135*7836SJohn.Forte@Sun.COM 		bucket->hb_inlist = 0;
136*7836SJohn.Forte@Sun.COM 	}
137*7836SJohn.Forte@Sun.COM 
138*7836SJohn.Forte@Sun.COM 	return (hash_table);
139*7836SJohn.Forte@Sun.COM }
140*7836SJohn.Forte@Sun.COM 
141*7836SJohn.Forte@Sun.COM 
142*7836SJohn.Forte@Sun.COM /*
143*7836SJohn.Forte@Sun.COM  * _sdbc_hash_deconfigure - deconfigure a hash table
144*7836SJohn.Forte@Sun.COM  *
145*7836SJohn.Forte@Sun.COM  * ARGUMENTS:
146*7836SJohn.Forte@Sun.COM  *	hash_table - hash table that was created earlier on.
147*7836SJohn.Forte@Sun.COM  *
148*7836SJohn.Forte@Sun.COM  * RETURNS:
149*7836SJohn.Forte@Sun.COM  *	None.
150*7836SJohn.Forte@Sun.COM  *
151*7836SJohn.Forte@Sun.COM  * USAGE:
152*7836SJohn.Forte@Sun.COM  *	this routine deallocates memory that was allocated during the
153*7836SJohn.Forte@Sun.COM  *	hash create.
154*7836SJohn.Forte@Sun.COM  */
155*7836SJohn.Forte@Sun.COM 
156*7836SJohn.Forte@Sun.COM void
_sdbc_hash_deconfigure(_sd_hash_table_t * hash_table)157*7836SJohn.Forte@Sun.COM _sdbc_hash_deconfigure(_sd_hash_table_t *hash_table)
158*7836SJohn.Forte@Sun.COM {
159*7836SJohn.Forte@Sun.COM 	if (!hash_table)
160*7836SJohn.Forte@Sun.COM 		return;
161*7836SJohn.Forte@Sun.COM 
162*7836SJohn.Forte@Sun.COM 	nsc_kmem_free(hash_table->ht_buckets,
163*7836SJohn.Forte@Sun.COM 			hash_table->ht_size * sizeof (_sd_hash_bucket_t));
164*7836SJohn.Forte@Sun.COM 
165*7836SJohn.Forte@Sun.COM 	nsc_kmem_free(hash_table, sizeof (_sd_hash_table_t));
166*7836SJohn.Forte@Sun.COM }
167*7836SJohn.Forte@Sun.COM 
168*7836SJohn.Forte@Sun.COM static int _sd_forced_hash_miss;
169*7836SJohn.Forte@Sun.COM static int _sd_hash_collision;
170*7836SJohn.Forte@Sun.COM 
171*7836SJohn.Forte@Sun.COM 
172*7836SJohn.Forte@Sun.COM /*
173*7836SJohn.Forte@Sun.COM  * _sd_hash_search - search the hash table for an entry
174*7836SJohn.Forte@Sun.COM  *
175*7836SJohn.Forte@Sun.COM  * ARGUMENTS:
176*7836SJohn.Forte@Sun.COM  *	cd	   - device that we are interested in.
177*7836SJohn.Forte@Sun.COM  *	block_num  - block number we are interested in.
178*7836SJohn.Forte@Sun.COM  *	hash_table - hash table to search in.
179*7836SJohn.Forte@Sun.COM  *
180*7836SJohn.Forte@Sun.COM  * RETURNS:
181*7836SJohn.Forte@Sun.COM  *	returns a hash header if a match was found in the hash table
182*7836SJohn.Forte@Sun.COM  *	for the device & block_num.
183*7836SJohn.Forte@Sun.COM  *	Else returns 0.
184*7836SJohn.Forte@Sun.COM  *
185*7836SJohn.Forte@Sun.COM  * USAGE:
186*7836SJohn.Forte@Sun.COM  *	This routine is called to check if a block already exists for
187*7836SJohn.Forte@Sun.COM  *	the device, block_num combination. If the block does not exist,
188*7836SJohn.Forte@Sun.COM  *	then a new block needs to be allocated and inserted into the hash
189*7836SJohn.Forte@Sun.COM  *	table for future references.
190*7836SJohn.Forte@Sun.COM  */
191*7836SJohn.Forte@Sun.COM 
192*7836SJohn.Forte@Sun.COM _sd_hash_hd_t *
_sd_hash_search(int cd,nsc_off_t block_num,_sd_hash_table_t * table)193*7836SJohn.Forte@Sun.COM _sd_hash_search(int cd, nsc_off_t block_num, _sd_hash_table_t *table)
194*7836SJohn.Forte@Sun.COM {
195*7836SJohn.Forte@Sun.COM 	int i;
196*7836SJohn.Forte@Sun.COM 	_sd_hash_bucket_t *bucket;
197*7836SJohn.Forte@Sun.COM 	_sd_hash_hd_t *hptr;
198*7836SJohn.Forte@Sun.COM #if defined(_SD_HASH_OPTIMIZE)
199*7836SJohn.Forte@Sun.COM #define	MAX_HSEARCH_RETRIES	30
200*7836SJohn.Forte@Sun.COM 	int tries = 0;
201*7836SJohn.Forte@Sun.COM 	_sd_hash_hd_t *hnext;
202*7836SJohn.Forte@Sun.COM 	unsigned int seq;
203*7836SJohn.Forte@Sun.COM 
204*7836SJohn.Forte@Sun.COM 	i = HASH(cd, block_num, table);
205*7836SJohn.Forte@Sun.COM 	bucket = (table->ht_buckets + i);
206*7836SJohn.Forte@Sun.COM retry_search:
207*7836SJohn.Forte@Sun.COM 	seq = bucket->hb_seq;
208*7836SJohn.Forte@Sun.COM 	for (hptr = bucket->hb_head; hptr; hptr = hnext) {
209*7836SJohn.Forte@Sun.COM 		/*
210*7836SJohn.Forte@Sun.COM 		 * Save pointer for next before checking the seq counter.
211*7836SJohn.Forte@Sun.COM 		 */
212*7836SJohn.Forte@Sun.COM 		hnext = hptr->hh_next;
213*7836SJohn.Forte@Sun.COM 		/*
214*7836SJohn.Forte@Sun.COM 		 * enforce ordering of load of hptr->hh_next
215*7836SJohn.Forte@Sun.COM 		 * above and bucket->hb_seq below
216*7836SJohn.Forte@Sun.COM 		 */
217*7836SJohn.Forte@Sun.COM 		sd_serialize();
218*7836SJohn.Forte@Sun.COM 		if (bucket->hb_seq != seq) {
219*7836SJohn.Forte@Sun.COM 			/*
220*7836SJohn.Forte@Sun.COM 			 * To avoid looping forever, break out if a certain
221*7836SJohn.Forte@Sun.COM 			 * limit is reached. Its okay to return miss
222*7836SJohn.Forte@Sun.COM 			 * since the insert will do a proper search.
223*7836SJohn.Forte@Sun.COM 			 */
224*7836SJohn.Forte@Sun.COM 			if (++tries < MAX_HSEARCH_RETRIES) goto retry_search;
225*7836SJohn.Forte@Sun.COM 			else {
226*7836SJohn.Forte@Sun.COM 				_sd_forced_hash_miss++;
227*7836SJohn.Forte@Sun.COM 				DTRACE_PROBE1(_sd_hash_search_end,
228*7836SJohn.Forte@Sun.COM 						int, _sd_forced_hash_miss);
229*7836SJohn.Forte@Sun.COM 				return (NULL);
230*7836SJohn.Forte@Sun.COM 			}
231*7836SJohn.Forte@Sun.COM 		}
232*7836SJohn.Forte@Sun.COM 		if ((hptr->hh_cd == cd) && (hptr->hh_blk_num == block_num))
233*7836SJohn.Forte@Sun.COM 			break;
234*7836SJohn.Forte@Sun.COM 		if (hptr->hh_blk_num > block_num) {
235*7836SJohn.Forte@Sun.COM 			DTRACE_PROBE1(_sd_hash_search_end,
236*7836SJohn.Forte@Sun.COM 					_sd_hash_hd_t *, hptr);
237*7836SJohn.Forte@Sun.COM 			return (NULL);
238*7836SJohn.Forte@Sun.COM 		}
239*7836SJohn.Forte@Sun.COM 	}
240*7836SJohn.Forte@Sun.COM 
241*7836SJohn.Forte@Sun.COM 	DTRACE_PROBE1(_sd_hash_search_end,
242*7836SJohn.Forte@Sun.COM 			_sd_hash_hd_t *, hptr);
243*7836SJohn.Forte@Sun.COM 	return (hptr);
244*7836SJohn.Forte@Sun.COM #else
245*7836SJohn.Forte@Sun.COM 
246*7836SJohn.Forte@Sun.COM 	i = HASH(cd, block_num, table);
247*7836SJohn.Forte@Sun.COM 	bucket = (table->ht_buckets + i);
248*7836SJohn.Forte@Sun.COM 
249*7836SJohn.Forte@Sun.COM 	mutex_enter(bucket->hb_lock);
250*7836SJohn.Forte@Sun.COM 
251*7836SJohn.Forte@Sun.COM 	for (hptr = bucket->hb_head; hptr; hptr = hptr->hh_next) {
252*7836SJohn.Forte@Sun.COM 		if ((hptr->hh_cd == cd) && (hptr->hh_blk_num == block_num))
253*7836SJohn.Forte@Sun.COM 			break;
254*7836SJohn.Forte@Sun.COM 		/*
255*7836SJohn.Forte@Sun.COM 		 * the list is ordered. If we go beyond our block, no
256*7836SJohn.Forte@Sun.COM 		 * point searching
257*7836SJohn.Forte@Sun.COM 		 */
258*7836SJohn.Forte@Sun.COM 		if (hptr->hh_blk_num > block_num) {
259*7836SJohn.Forte@Sun.COM 			hptr = NULL;
260*7836SJohn.Forte@Sun.COM 			break;
261*7836SJohn.Forte@Sun.COM 		}
262*7836SJohn.Forte@Sun.COM 	}
263*7836SJohn.Forte@Sun.COM 	mutex_exit(bucket->hb_lock);
264*7836SJohn.Forte@Sun.COM 
265*7836SJohn.Forte@Sun.COM 	return (hptr);
266*7836SJohn.Forte@Sun.COM #endif
267*7836SJohn.Forte@Sun.COM }
268*7836SJohn.Forte@Sun.COM 
269*7836SJohn.Forte@Sun.COM 
270*7836SJohn.Forte@Sun.COM /*
271*7836SJohn.Forte@Sun.COM  * _sd_hash_insert - insert an entry into the hash table
272*7836SJohn.Forte@Sun.COM  *
273*7836SJohn.Forte@Sun.COM  * ARGUMENTS:
274*7836SJohn.Forte@Sun.COM  *	cd	   - device that we are interested in.
275*7836SJohn.Forte@Sun.COM  *	block_num  - block number we are interested in.
276*7836SJohn.Forte@Sun.COM  *      hptr       - pointer to block that we are inserting.
277*7836SJohn.Forte@Sun.COM  *	table	   - hash table to search in.
278*7836SJohn.Forte@Sun.COM  *
279*7836SJohn.Forte@Sun.COM  * RETURNS:
280*7836SJohn.Forte@Sun.COM  *	Pointer to block that was passed in, except if the cd, block_num
281*7836SJohn.Forte@Sun.COM  *	already exists in the hash.  Caller must check for return
282*7836SJohn.Forte@Sun.COM  *	not equal hptr.
283*7836SJohn.Forte@Sun.COM  *
284*7836SJohn.Forte@Sun.COM  * USAGE:
285*7836SJohn.Forte@Sun.COM  *	this routine inserts the hptr into the appropriate hash bucket and
286*7836SJohn.Forte@Sun.COM  *	sets the cd, block_num in the block for future references.
287*7836SJohn.Forte@Sun.COM  */
288*7836SJohn.Forte@Sun.COM 
289*7836SJohn.Forte@Sun.COM _sd_hash_hd_t *
_sd_hash_insert(int cd,nsc_off_t block_num,_sd_hash_hd_t * hptr,_sd_hash_table_t * table)290*7836SJohn.Forte@Sun.COM _sd_hash_insert(int cd,
291*7836SJohn.Forte@Sun.COM 		nsc_off_t block_num,
292*7836SJohn.Forte@Sun.COM 		_sd_hash_hd_t *hptr,
293*7836SJohn.Forte@Sun.COM 		_sd_hash_table_t *table)
294*7836SJohn.Forte@Sun.COM {
295*7836SJohn.Forte@Sun.COM 	int i;
296*7836SJohn.Forte@Sun.COM 	_sd_hash_hd_t *p;
297*7836SJohn.Forte@Sun.COM 	_sd_hash_bucket_t *bucket;
298*7836SJohn.Forte@Sun.COM 
299*7836SJohn.Forte@Sun.COM 	i = HASH(cd, block_num, table);
300*7836SJohn.Forte@Sun.COM 	bucket = (table->ht_buckets + i);
301*7836SJohn.Forte@Sun.COM 
302*7836SJohn.Forte@Sun.COM #if defined(_SD_DEBUG)
303*7836SJohn.Forte@Sun.COM 	if (hptr->hh_hashed) {
304*7836SJohn.Forte@Sun.COM 		cmn_err(CE_WARN, "_sd_err: hptr %p bucket %p already hashed",
305*7836SJohn.Forte@Sun.COM 			hptr, bucket);
306*7836SJohn.Forte@Sun.COM 	}
307*7836SJohn.Forte@Sun.COM #endif
308*7836SJohn.Forte@Sun.COM 	hptr->hh_cd = (ushort_t)cd;
309*7836SJohn.Forte@Sun.COM 	hptr->hh_blk_num = block_num;
310*7836SJohn.Forte@Sun.COM 
311*7836SJohn.Forte@Sun.COM 	mutex_enter(bucket->hb_lock);
312*7836SJohn.Forte@Sun.COM 
313*7836SJohn.Forte@Sun.COM 	for (p = bucket->hb_head; (p && (p->hh_blk_num <= block_num));
314*7836SJohn.Forte@Sun.COM 							p = p->hh_next) {
315*7836SJohn.Forte@Sun.COM 		if ((p->hh_cd == cd) && (p->hh_blk_num == block_num)) {
316*7836SJohn.Forte@Sun.COM 			mutex_exit(bucket->hb_lock);
317*7836SJohn.Forte@Sun.COM 			_sd_hash_collision++;
318*7836SJohn.Forte@Sun.COM 			DTRACE_PROBE2(_sd_hash_insert_end,
319*7836SJohn.Forte@Sun.COM 					_sd_hash_hd_t *, p,
320*7836SJohn.Forte@Sun.COM 					int, _sd_hash_collision);
321*7836SJohn.Forte@Sun.COM 
322*7836SJohn.Forte@Sun.COM 			return (p);
323*7836SJohn.Forte@Sun.COM 		}
324*7836SJohn.Forte@Sun.COM 	}
325*7836SJohn.Forte@Sun.COM 	hptr->hh_hashed = 1;
326*7836SJohn.Forte@Sun.COM 	/*
327*7836SJohn.Forte@Sun.COM 	 * At this point, (p) points to the next higher block number or is
328*7836SJohn.Forte@Sun.COM 	 * NULL. If it is NULL, we are queueing to the tail of list.
329*7836SJohn.Forte@Sun.COM 	 * Else, insert just before p
330*7836SJohn.Forte@Sun.COM 	 */
331*7836SJohn.Forte@Sun.COM 	if (p) {
332*7836SJohn.Forte@Sun.COM 		hptr->hh_next = p;
333*7836SJohn.Forte@Sun.COM 		if ((hptr->hh_prev = p->hh_prev) != NULL)
334*7836SJohn.Forte@Sun.COM 			p->hh_prev->hh_next = hptr;
335*7836SJohn.Forte@Sun.COM 		else
336*7836SJohn.Forte@Sun.COM 			bucket->hb_head = hptr;
337*7836SJohn.Forte@Sun.COM 		p->hh_prev = hptr;
338*7836SJohn.Forte@Sun.COM 	} else {
339*7836SJohn.Forte@Sun.COM 		hptr->hh_next = NULL;
340*7836SJohn.Forte@Sun.COM 		hptr->hh_prev = bucket->hb_tail;
341*7836SJohn.Forte@Sun.COM 		if (bucket->hb_head)
342*7836SJohn.Forte@Sun.COM 			bucket->hb_tail->hh_next = hptr;
343*7836SJohn.Forte@Sun.COM 		else
344*7836SJohn.Forte@Sun.COM 			bucket->hb_head = hptr;
345*7836SJohn.Forte@Sun.COM 		bucket->hb_tail = hptr;
346*7836SJohn.Forte@Sun.COM 	}
347*7836SJohn.Forte@Sun.COM #if defined(_SD_HASH_OPTIMIZE)
348*7836SJohn.Forte@Sun.COM 	bucket->hb_seq++;
349*7836SJohn.Forte@Sun.COM #endif
350*7836SJohn.Forte@Sun.COM #if defined(_SD_DEBUG)
351*7836SJohn.Forte@Sun.COM 	if (_sd_hash_max_inlist < (int)++(bucket->hb_inlist))
352*7836SJohn.Forte@Sun.COM 		_sd_hash_max_inlist = bucket->hb_inlist;
353*7836SJohn.Forte@Sun.COM #endif
354*7836SJohn.Forte@Sun.COM 	mutex_exit(bucket->hb_lock);
355*7836SJohn.Forte@Sun.COM 
356*7836SJohn.Forte@Sun.COM 	return (hptr);
357*7836SJohn.Forte@Sun.COM }
358*7836SJohn.Forte@Sun.COM 
359*7836SJohn.Forte@Sun.COM 
360*7836SJohn.Forte@Sun.COM 
361*7836SJohn.Forte@Sun.COM /*
362*7836SJohn.Forte@Sun.COM  * _sd_hash_delete - delete an entry from the hash table
363*7836SJohn.Forte@Sun.COM  *
364*7836SJohn.Forte@Sun.COM  * ARGUMENTS:
365*7836SJohn.Forte@Sun.COM  *	hptr	   - pointer to delete from hash table.
366*7836SJohn.Forte@Sun.COM  *	hash_table - hash table that was created earlier on.
367*7836SJohn.Forte@Sun.COM  *
368*7836SJohn.Forte@Sun.COM  * RETURNS:
369*7836SJohn.Forte@Sun.COM  *	0 on success.  -1 on errors.
370*7836SJohn.Forte@Sun.COM  *
371*7836SJohn.Forte@Sun.COM  * USAGE:
372*7836SJohn.Forte@Sun.COM  *	this routine deletes a hash entry from the hash table.
373*7836SJohn.Forte@Sun.COM  */
374*7836SJohn.Forte@Sun.COM 
375*7836SJohn.Forte@Sun.COM int
_sd_hash_delete(_sd_hash_hd_t * hptr,_sd_hash_table_t * table)376*7836SJohn.Forte@Sun.COM _sd_hash_delete(_sd_hash_hd_t *hptr, _sd_hash_table_t *table)
377*7836SJohn.Forte@Sun.COM {
378*7836SJohn.Forte@Sun.COM 	int i;
379*7836SJohn.Forte@Sun.COM 	_sd_hash_bucket_t *bucket;
380*7836SJohn.Forte@Sun.COM 
381*7836SJohn.Forte@Sun.COM 	if (hptr->hh_hashed == 0) {
382*7836SJohn.Forte@Sun.COM 		DTRACE_PROBE(_sd_hash_delete_end1);
383*7836SJohn.Forte@Sun.COM 		return (-1);
384*7836SJohn.Forte@Sun.COM 	}
385*7836SJohn.Forte@Sun.COM 
386*7836SJohn.Forte@Sun.COM 	i = HASH(hptr->hh_cd, hptr->hh_blk_num, table);
387*7836SJohn.Forte@Sun.COM 	bucket = (table->ht_buckets + i);
388*7836SJohn.Forte@Sun.COM 
389*7836SJohn.Forte@Sun.COM 	/* was FAST */
390*7836SJohn.Forte@Sun.COM 	mutex_enter(bucket->hb_lock);
391*7836SJohn.Forte@Sun.COM 	if (hptr->hh_hashed == 0) {
392*7836SJohn.Forte@Sun.COM 		/* was FAST */
393*7836SJohn.Forte@Sun.COM 		mutex_exit(bucket->hb_lock);
394*7836SJohn.Forte@Sun.COM 		DTRACE_PROBE(_sd_hash_delete_end2);
395*7836SJohn.Forte@Sun.COM 		return (-1);
396*7836SJohn.Forte@Sun.COM 	}
397*7836SJohn.Forte@Sun.COM 	hptr->hh_hashed = 0;
398*7836SJohn.Forte@Sun.COM #if defined(_SD_HASH_OPTIMIZE)
399*7836SJohn.Forte@Sun.COM 	/*
400*7836SJohn.Forte@Sun.COM 	 * Increment sequence counter on bucket. This will signal a lookup
401*7836SJohn.Forte@Sun.COM 	 * to redo the lookup since we might have broken the link used
402*7836SJohn.Forte@Sun.COM 	 * during the lookup.
403*7836SJohn.Forte@Sun.COM 	 */
404*7836SJohn.Forte@Sun.COM 	bucket->hb_seq++;
405*7836SJohn.Forte@Sun.COM #endif
406*7836SJohn.Forte@Sun.COM 
407*7836SJohn.Forte@Sun.COM 	if (hptr->hh_prev)
408*7836SJohn.Forte@Sun.COM 		hptr->hh_prev->hh_next = hptr->hh_next;
409*7836SJohn.Forte@Sun.COM 	else
410*7836SJohn.Forte@Sun.COM 		bucket->hb_head = hptr->hh_next;
411*7836SJohn.Forte@Sun.COM 	if (hptr->hh_next)
412*7836SJohn.Forte@Sun.COM 		hptr->hh_next->hh_prev = hptr->hh_prev;
413*7836SJohn.Forte@Sun.COM 	else
414*7836SJohn.Forte@Sun.COM 		bucket->hb_tail = hptr->hh_prev;
415*7836SJohn.Forte@Sun.COM #if defined(_SD_DEBUG)
416*7836SJohn.Forte@Sun.COM 	bucket->hb_inlist--;
417*7836SJohn.Forte@Sun.COM #endif
418*7836SJohn.Forte@Sun.COM 	/* was FAST */
419*7836SJohn.Forte@Sun.COM 	mutex_exit(bucket->hb_lock);
420*7836SJohn.Forte@Sun.COM 
421*7836SJohn.Forte@Sun.COM 	return (0);
422*7836SJohn.Forte@Sun.COM }
423*7836SJohn.Forte@Sun.COM 
424*7836SJohn.Forte@Sun.COM /*
425*7836SJohn.Forte@Sun.COM  * _sd_hash_replace - replace 'old' with 'new' entry.
426*7836SJohn.Forte@Sun.COM  *
427*7836SJohn.Forte@Sun.COM  * ARGUMENTS:
428*7836SJohn.Forte@Sun.COM  *      old   - pointer to block being deleted (to be anonymous)
429*7836SJohn.Forte@Sun.COM  *      new   - pointer to block inserting in place.
430*7836SJohn.Forte@Sun.COM  *	table - hash table to search in.
431*7836SJohn.Forte@Sun.COM  *
432*7836SJohn.Forte@Sun.COM  * RETURNS:
433*7836SJohn.Forte@Sun.COM  *	pointer to inserted block.
434*7836SJohn.Forte@Sun.COM  *
435*7836SJohn.Forte@Sun.COM  * USAGE:
436*7836SJohn.Forte@Sun.COM  *	expects old & new to refer to same block.
437*7836SJohn.Forte@Sun.COM  *	new must not be already hashed.
438*7836SJohn.Forte@Sun.COM  */
439*7836SJohn.Forte@Sun.COM 
440*7836SJohn.Forte@Sun.COM _sd_hash_hd_t *
_sd_hash_replace(_sd_hash_hd_t * old,_sd_hash_hd_t * new,_sd_hash_table_t * table)441*7836SJohn.Forte@Sun.COM _sd_hash_replace(_sd_hash_hd_t *old, _sd_hash_hd_t *new,
442*7836SJohn.Forte@Sun.COM 			_sd_hash_table_t *table)
443*7836SJohn.Forte@Sun.COM {
444*7836SJohn.Forte@Sun.COM 	int i;
445*7836SJohn.Forte@Sun.COM 	_sd_hash_bucket_t *bucket;
446*7836SJohn.Forte@Sun.COM 
447*7836SJohn.Forte@Sun.COM 	if ((old->hh_cd != new->hh_cd) || (old->hh_blk_num != new->hh_blk_num))
448*7836SJohn.Forte@Sun.COM 		cmn_err(CE_PANIC, "_sd_hash_replace: mismatch %p %p",
449*7836SJohn.Forte@Sun.COM 		    (void *)old, (void *)new);
450*7836SJohn.Forte@Sun.COM 	if (new->hh_hashed)
451*7836SJohn.Forte@Sun.COM 		cmn_err(CE_PANIC, "_sd_hash_replace: new %p already hashed",
452*7836SJohn.Forte@Sun.COM 		    (void *)new);
453*7836SJohn.Forte@Sun.COM 	if (old->hh_hashed == 0) {
454*7836SJohn.Forte@Sun.COM 		_sd_hash_hd_t *hptr;
455*7836SJohn.Forte@Sun.COM 		hptr = _sd_hash_insert(new->hh_cd, new->hh_blk_num, new, table);
456*7836SJohn.Forte@Sun.COM 
457*7836SJohn.Forte@Sun.COM 		DTRACE_PROBE1(_sd_hash_replace_end,
458*7836SJohn.Forte@Sun.COM 				_sd_hash_hd_t *, hptr);
459*7836SJohn.Forte@Sun.COM 
460*7836SJohn.Forte@Sun.COM 		return (hptr);
461*7836SJohn.Forte@Sun.COM 	}
462*7836SJohn.Forte@Sun.COM 
463*7836SJohn.Forte@Sun.COM 	i = HASH(old->hh_cd, old->hh_blk_num, table);
464*7836SJohn.Forte@Sun.COM 	bucket = (table->ht_buckets + i);
465*7836SJohn.Forte@Sun.COM 
466*7836SJohn.Forte@Sun.COM 	/* was FAST */
467*7836SJohn.Forte@Sun.COM 	mutex_enter(bucket->hb_lock);
468*7836SJohn.Forte@Sun.COM 	if (old->hh_hashed == 0) {
469*7836SJohn.Forte@Sun.COM 		_sd_hash_hd_t *hptr;
470*7836SJohn.Forte@Sun.COM 		/* was FAST */
471*7836SJohn.Forte@Sun.COM 		mutex_exit(bucket->hb_lock);
472*7836SJohn.Forte@Sun.COM 
473*7836SJohn.Forte@Sun.COM 		hptr = _sd_hash_insert(new->hh_cd, new->hh_blk_num, new, table);
474*7836SJohn.Forte@Sun.COM 
475*7836SJohn.Forte@Sun.COM 		DTRACE_PROBE1(_sd_hash_replace_end,
476*7836SJohn.Forte@Sun.COM 				_sd_hash_hd_t *, hptr);
477*7836SJohn.Forte@Sun.COM 		return (hptr);
478*7836SJohn.Forte@Sun.COM 	}
479*7836SJohn.Forte@Sun.COM 	old->hh_hashed = 0;
480*7836SJohn.Forte@Sun.COM 	new->hh_hashed = 1;
481*7836SJohn.Forte@Sun.COM 	new->hh_prev = old->hh_prev;
482*7836SJohn.Forte@Sun.COM 	new->hh_next = old->hh_next;
483*7836SJohn.Forte@Sun.COM 
484*7836SJohn.Forte@Sun.COM 	if (new->hh_prev)
485*7836SJohn.Forte@Sun.COM 		new->hh_prev->hh_next = new;
486*7836SJohn.Forte@Sun.COM 	else
487*7836SJohn.Forte@Sun.COM 		bucket->hb_head = new;
488*7836SJohn.Forte@Sun.COM 	if (new->hh_next)
489*7836SJohn.Forte@Sun.COM 		new->hh_next->hh_prev = new;
490*7836SJohn.Forte@Sun.COM 	else
491*7836SJohn.Forte@Sun.COM 		bucket->hb_tail = new;
492*7836SJohn.Forte@Sun.COM #if defined(_SD_HASH_OPTIMIZE)
493*7836SJohn.Forte@Sun.COM 	bucket->hb_seq++;
494*7836SJohn.Forte@Sun.COM #endif
495*7836SJohn.Forte@Sun.COM 	/* was FAST */
496*7836SJohn.Forte@Sun.COM 	mutex_exit(bucket->hb_lock);
497*7836SJohn.Forte@Sun.COM 
498*7836SJohn.Forte@Sun.COM 	return (new);
499*7836SJohn.Forte@Sun.COM }
500