xref: /titanic_50/usr/src/cmd/ndmpd/tlm/tlm_bitmap.c (revision 47842382d52f28aa3173aa6b511781c322ccb6a2)
1*2654012fSReza Sabdar /*
2*2654012fSReza Sabdar  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3*2654012fSReza Sabdar  * Use is subject to license terms.
4*2654012fSReza Sabdar  */
5*2654012fSReza Sabdar 
6*2654012fSReza Sabdar /*
7*2654012fSReza Sabdar  * BSD 3 Clause License
8*2654012fSReza Sabdar  *
9*2654012fSReza Sabdar  * Copyright (c) 2007, The Storage Networking Industry Association.
10*2654012fSReza Sabdar  *
11*2654012fSReza Sabdar  * Redistribution and use in source and binary forms, with or without
12*2654012fSReza Sabdar  * modification, are permitted provided that the following conditions
13*2654012fSReza Sabdar  * are met:
14*2654012fSReza Sabdar  * 	- Redistributions of source code must retain the above copyright
15*2654012fSReza Sabdar  *	  notice, this list of conditions and the following disclaimer.
16*2654012fSReza Sabdar  *
17*2654012fSReza Sabdar  * 	- Redistributions in binary form must reproduce the above copyright
18*2654012fSReza Sabdar  *	  notice, this list of conditions and the following disclaimer in
19*2654012fSReza Sabdar  *	  the documentation and/or other materials provided with the
20*2654012fSReza Sabdar  *	  distribution.
21*2654012fSReza Sabdar  *
22*2654012fSReza Sabdar  *	- Neither the name of The Storage Networking Industry Association (SNIA)
23*2654012fSReza Sabdar  *	  nor the names of its contributors may be used to endorse or promote
24*2654012fSReza Sabdar  *	  products derived from this software without specific prior written
25*2654012fSReza Sabdar  *	  permission.
26*2654012fSReza Sabdar  *
27*2654012fSReza Sabdar  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28*2654012fSReza Sabdar  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29*2654012fSReza Sabdar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30*2654012fSReza Sabdar  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31*2654012fSReza Sabdar  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32*2654012fSReza Sabdar  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33*2654012fSReza Sabdar  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34*2654012fSReza Sabdar  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35*2654012fSReza Sabdar  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36*2654012fSReza Sabdar  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37*2654012fSReza Sabdar  * POSSIBILITY OF SUCH DAMAGE.
38*2654012fSReza Sabdar  */
39*2654012fSReza Sabdar #include <sys/types.h>
40*2654012fSReza Sabdar #include <sys/queue.h>
41*2654012fSReza Sabdar #include <bitmap.h>
42*2654012fSReza Sabdar #include <fcntl.h>
43*2654012fSReza Sabdar #include <stdio.h>
44*2654012fSReza Sabdar #include <stdlib.h>
45*2654012fSReza Sabdar #include <string.h>
46*2654012fSReza Sabdar #include <time.h>
47*2654012fSReza Sabdar #include <unistd.h>
48*2654012fSReza Sabdar #include <tlm.h>
49*2654012fSReza Sabdar 
50*2654012fSReza Sabdar 
51*2654012fSReza Sabdar /*
52*2654012fSReza Sabdar  * Hash table size.
53*2654012fSReza Sabdar  */
54*2654012fSReza Sabdar #define	BMAP_HASH_SIZE		64
55*2654012fSReza Sabdar 
56*2654012fSReza Sabdar 
57*2654012fSReza Sabdar /*
58*2654012fSReza Sabdar  * Maximum number of chunk that can be cached.
59*2654012fSReza Sabdar  */
60*2654012fSReza Sabdar #define	BMAP_CHUNK_MAX		128
61*2654012fSReza Sabdar 
62*2654012fSReza Sabdar 
63*2654012fSReza Sabdar /*
64*2654012fSReza Sabdar  * Size of bitmap table.
65*2654012fSReza Sabdar  */
66*2654012fSReza Sabdar #define	BMAP_MAX	256
67*2654012fSReza Sabdar 
68*2654012fSReza Sabdar 
69*2654012fSReza Sabdar /*
70*2654012fSReza Sabdar  * Bit_MAP Word SIZE.  This should be equal to 'sizeof (int)'.
71*2654012fSReza Sabdar  */
72*2654012fSReza Sabdar #define	BMAP_WSIZE	(sizeof (int))
73*2654012fSReza Sabdar 
74*2654012fSReza Sabdar 
75*2654012fSReza Sabdar /*
76*2654012fSReza Sabdar  * Bit_MAP Bit Per Word.
77*2654012fSReza Sabdar  */
78*2654012fSReza Sabdar #define	BMAP_BPW	(BMAP_WSIZE * 8)
79*2654012fSReza Sabdar #define	BMAP_BPW_SHIFT	5
80*2654012fSReza Sabdar #define	BMAP_BPW_MASK	(~(~0 << BMAP_BPW_SHIFT))
81*2654012fSReza Sabdar 
82*2654012fSReza Sabdar 
83*2654012fSReza Sabdar /*
84*2654012fSReza Sabdar  * Chunk of bit map in each node.
85*2654012fSReza Sabdar  */
86*2654012fSReza Sabdar #define	BMAP_CHUNK_WORDS	1024
87*2654012fSReza Sabdar #define	BMAP_CHUNK_BYTES	(BMAP_CHUNK_WORDS * BMAP_WSIZE)
88*2654012fSReza Sabdar #define	BMAP_CHUNK_BITS		(BMAP_CHUNK_WORDS * BMAP_BPW)
89*2654012fSReza Sabdar #define	BMAP_CHUNK_NO(p)	((p) / BMAP_CHUNK_BITS)
90*2654012fSReza Sabdar #define	BMAP_CHUNK_OFF(p)	(BMAP_CHUNK_NO(p) * BMAP_CHUNK_BITS)
91*2654012fSReza Sabdar 
92*2654012fSReza Sabdar 
93*2654012fSReza Sabdar /*
94*2654012fSReza Sabdar  * Bitmap flags.
95*2654012fSReza Sabdar  */
96*2654012fSReza Sabdar #define	BMAP_BINIT_ONES	0x00000001 /* initial value of bits is 1 */
97*2654012fSReza Sabdar #define	BMAP_INUSE	0x00000002 /* slot is in use */
98*2654012fSReza Sabdar 
99*2654012fSReza Sabdar 
100*2654012fSReza Sabdar /*
101*2654012fSReza Sabdar  * Macros of bitmap flags.
102*2654012fSReza Sabdar  */
103*2654012fSReza Sabdar #define	BMAP_SET_FLAGS(b, f)	((b)->bm_flags |= (f))
104*2654012fSReza Sabdar #define	BMAP_UNSET_FLAGS(b, f)	((b)->bm_flags &= ~(f))
105*2654012fSReza Sabdar 
106*2654012fSReza Sabdar #define	BMAP_IS_INIT_ONES(b)	((b)->bm_flags & BMAP_BINIT_ONES)
107*2654012fSReza Sabdar #define	BMAP_IS_INUSE(b)	((b)->bm_flags & BMAP_INUSE)
108*2654012fSReza Sabdar 
109*2654012fSReza Sabdar 
110*2654012fSReza Sabdar #define	HASH(p)		(((p) / BMAP_CHUNK_BITS) % BMAP_HASH_SIZE)
111*2654012fSReza Sabdar 
112*2654012fSReza Sabdar /*
113*2654012fSReza Sabdar  * Calculate the memory size in bytes needed for the specified length
114*2654012fSReza Sabdar  * of bitmap.
115*2654012fSReza Sabdar  */
116*2654012fSReza Sabdar #define	ROUNDUP(n, d)	(((n) + (d) - 1) / (d))
117*2654012fSReza Sabdar #define	MEM_LEN(l)	(ROUNDUP((l), BMAP_BPW) * BMAP_WSIZE)
118*2654012fSReza Sabdar 
119*2654012fSReza Sabdar 
120*2654012fSReza Sabdar /*
121*2654012fSReza Sabdar  * Chunk flags.
122*2654012fSReza Sabdar  */
123*2654012fSReza Sabdar #define	BMAP_CSET_DIRTY(cp)	(cp)->c_flags |= BMAP_CDIRTY
124*2654012fSReza Sabdar #define	BMAP_CDIRTY	0x00000001 /* the chunk is dirty */
125*2654012fSReza Sabdar 
126*2654012fSReza Sabdar 
127*2654012fSReza Sabdar /*
128*2654012fSReza Sabdar  * Macros on chunk flags.
129*2654012fSReza Sabdar  */
130*2654012fSReza Sabdar #define	BMAP_CIS_DIRTY(cp)	((cp)->c_flags & BMAP_CDIRTY)
131*2654012fSReza Sabdar 
132*2654012fSReza Sabdar 
133*2654012fSReza Sabdar /*
134*2654012fSReza Sabdar  * When loading a bitmap chunk, if it is new set the bitmap
135*2654012fSReza Sabdar  * can be set according to the initial value of bits.
136*2654012fSReza Sabdar  * Otherwise, it should be loaded from the file.
137*2654012fSReza Sabdar  */
138*2654012fSReza Sabdar #define	BMAP_NEW_CHUNK		1
139*2654012fSReza Sabdar #define	BMAP_OLD_CHUNK		0
140*2654012fSReza Sabdar 
141*2654012fSReza Sabdar /*
142*2654012fSReza Sabdar  * Each chunk holds the followin information:
143*2654012fSReza Sabdar  *  - A flag showing the status of the chunk, like being ditry or not.
144*2654012fSReza Sabdar  *  - Its offset in bits from the beginning of the vector.
145*2654012fSReza Sabdar  *  - Its length in bits.
146*2654012fSReza Sabdar  *  - Its memory length in use in bytes.
147*2654012fSReza Sabdar  *  - The bitmap vector.
148*2654012fSReza Sabdar  *
149*2654012fSReza Sabdar  *  In addition to the above information, each chunk can be on two lists:
150*2654012fSReza Sabdar  *  one the hash list, the other LRU list.  The hash list is a MRU list,
151*2654012fSReza Sabdar  *  meaning the MRU entry is at the head of the list.
152*2654012fSReza Sabdar  *
153*2654012fSReza Sabdar  *  All the chunks are in the LRU list. When a chunk is needed and there is
154*2654012fSReza Sabdar  *  no more room for allocating chunks, the first entry of this list is
155*2654012fSReza Sabdar  *  reclaimed.
156*2654012fSReza Sabdar  */
157*2654012fSReza Sabdar typedef struct dbmap_chunk {
158*2654012fSReza Sabdar 	TAILQ_ENTRY(dbmap_chunk) c_hash;
159*2654012fSReza Sabdar 	TAILQ_ENTRY(dbmap_chunk) c_lru;
160*2654012fSReza Sabdar 	uint_t c_flags;
161*2654012fSReza Sabdar 	u_quad_t c_off;
162*2654012fSReza Sabdar 	uint_t c_clen;
163*2654012fSReza Sabdar 	uint_t c_mlen;
164*2654012fSReza Sabdar 	uint_t *c_bmp;
165*2654012fSReza Sabdar } dbmap_chunk_t;
166*2654012fSReza Sabdar 
167*2654012fSReza Sabdar 
168*2654012fSReza Sabdar TAILQ_HEAD(dbmap_list, dbmap_chunk);
169*2654012fSReza Sabdar typedef struct dbmap_list dbmap_list_t;
170*2654012fSReza Sabdar 
171*2654012fSReza Sabdar 
172*2654012fSReza Sabdar typedef struct dbitmap {
173*2654012fSReza Sabdar 	char *bm_fname;
174*2654012fSReza Sabdar 	int bm_fd;
175*2654012fSReza Sabdar 	uint_t bm_flags;
176*2654012fSReza Sabdar 	u_quad_t bm_len; /* bitmap length */
177*2654012fSReza Sabdar 	uint_t bm_cmax; /* maximum number of cached chunks */
178*2654012fSReza Sabdar 	uint_t bm_ccur; /* current number of cached chunks */
179*2654012fSReza Sabdar 	dbmap_list_t bm_hash[BMAP_HASH_SIZE]; /* MRU hash table */
180*2654012fSReza Sabdar 	dbmap_list_t bm_lru; /* LRU list */
181*2654012fSReza Sabdar } dbitmap_t;
182*2654012fSReza Sabdar 
183*2654012fSReza Sabdar /*
184*2654012fSReza Sabdar  * Disk bitmap table.  Upon allocating a dbitmap, one slot
185*2654012fSReza Sabdar  * of this table will be used.
186*2654012fSReza Sabdar  */
187*2654012fSReza Sabdar static dbitmap_t dbitmap[BMAP_MAX];
188*2654012fSReza Sabdar 
189*2654012fSReza Sabdar 
190*2654012fSReza Sabdar /*
191*2654012fSReza Sabdar  * Each chunk holds the followin information:
192*2654012fSReza Sabdar  *  - Its offset in bits from the beginning of the vector.
193*2654012fSReza Sabdar  *  - Its length in bits.
194*2654012fSReza Sabdar  *  - Its memory length in use in bytes.
195*2654012fSReza Sabdar  *  - The bitmap vector.
196*2654012fSReza Sabdar  *
197*2654012fSReza Sabdar  *  In addition to the above information, each chunk can be on a list:
198*2654012fSReza Sabdar  *  one the hash list.  The hash list is a MRU list,  meaning that the
199*2654012fSReza Sabdar  *  MRU entry is at the head of the list.
200*2654012fSReza Sabdar  */
201*2654012fSReza Sabdar typedef struct bmap_chunk {
202*2654012fSReza Sabdar 	TAILQ_ENTRY(bmap_chunk) c_hash;
203*2654012fSReza Sabdar 	u_quad_t c_off;
204*2654012fSReza Sabdar 	uint_t c_clen;
205*2654012fSReza Sabdar 	uint_t c_mlen;
206*2654012fSReza Sabdar 	uint_t *c_bmp;
207*2654012fSReza Sabdar } bmap_chunk_t;
208*2654012fSReza Sabdar 
209*2654012fSReza Sabdar 
210*2654012fSReza Sabdar TAILQ_HEAD(bmap_list, bmap_chunk);
211*2654012fSReza Sabdar typedef struct bmap_list bmap_list_t;
212*2654012fSReza Sabdar 
213*2654012fSReza Sabdar 
214*2654012fSReza Sabdar typedef struct bitmap {
215*2654012fSReza Sabdar 	uint_t bm_flags;
216*2654012fSReza Sabdar 	u_quad_t bm_len; /* bitmap length */
217*2654012fSReza Sabdar 	uint_t bm_cmax; /* maximum number of cached chunks */
218*2654012fSReza Sabdar 	uint_t bm_ccur; /* current number of cached chunks */
219*2654012fSReza Sabdar 	bmap_list_t bm_hash[BMAP_HASH_SIZE]; /* MRU hash table */
220*2654012fSReza Sabdar } bitmap_t;
221*2654012fSReza Sabdar 
222*2654012fSReza Sabdar 
223*2654012fSReza Sabdar /*
224*2654012fSReza Sabdar  * Statistics gathering structure.
225*2654012fSReza Sabdar  */
226*2654012fSReza Sabdar typedef struct bitmap_stats {
227*2654012fSReza Sabdar 	ulong_t bs_alloc_cnt;
228*2654012fSReza Sabdar 	ulong_t bs_alloc_size;
229*2654012fSReza Sabdar 	ulong_t bs_free_cnt;
230*2654012fSReza Sabdar 	ulong_t bs_set_applied;
231*2654012fSReza Sabdar 	ulong_t bs_unset_applied;
232*2654012fSReza Sabdar 	ulong_t bs_cache_hit;
233*2654012fSReza Sabdar 	ulong_t bs_cache_miss;
234*2654012fSReza Sabdar 	ulong_t bs_chunk_new;
235*2654012fSReza Sabdar 	ulong_t bs_chunk_flush;
236*2654012fSReza Sabdar 	ulong_t bs_chunk_reclaim;
237*2654012fSReza Sabdar 	u_quad_t bs_get;
238*2654012fSReza Sabdar 	u_quad_t bs_get_bits;
239*2654012fSReza Sabdar 	u_quad_t bs_set;
240*2654012fSReza Sabdar 	u_quad_t bs_set_bits;
241*2654012fSReza Sabdar 	u_quad_t bs_unset;
242*2654012fSReza Sabdar 	u_quad_t bs_unset_bits;
243*2654012fSReza Sabdar } bitmap_stats_t;
244*2654012fSReza Sabdar 
245*2654012fSReza Sabdar 
246*2654012fSReza Sabdar /*
247*2654012fSReza Sabdar  * Disk bitmap table.  Upon allocating a bitmap, one slot
248*2654012fSReza Sabdar  * of this table will be used.
249*2654012fSReza Sabdar  */
250*2654012fSReza Sabdar static bitmap_t bitmap[BMAP_MAX];
251*2654012fSReza Sabdar 
252*2654012fSReza Sabdar 
253*2654012fSReza Sabdar /*
254*2654012fSReza Sabdar  * Global instance of statistics variable.
255*2654012fSReza Sabdar  */
256*2654012fSReza Sabdar bitmap_stats_t bitmap_stats;
257*2654012fSReza Sabdar 
258*2654012fSReza Sabdar 
259*2654012fSReza Sabdar /*
260*2654012fSReza Sabdar  * bmd2bmp
261*2654012fSReza Sabdar  *
262*2654012fSReza Sabdar  * Convert bitmap descriptor to bitmap pointer.
263*2654012fSReza Sabdar  */
264*2654012fSReza Sabdar static bitmap_t *
bmd2bmp(int bmd)265*2654012fSReza Sabdar bmd2bmp(int bmd)
266*2654012fSReza Sabdar {
267*2654012fSReza Sabdar 	if (bmd < 0 || bmd >= BMAP_MAX)
268*2654012fSReza Sabdar 		return (NULL);
269*2654012fSReza Sabdar 
270*2654012fSReza Sabdar 	return (&bitmap[bmd]);
271*2654012fSReza Sabdar }
272*2654012fSReza Sabdar 
273*2654012fSReza Sabdar 
274*2654012fSReza Sabdar /*
275*2654012fSReza Sabdar  * bmd_alloc
276*2654012fSReza Sabdar  *
277*2654012fSReza Sabdar  * Allocate a bitmap descriptor.  Sets the INUSE flag of the slot.
278*2654012fSReza Sabdar  */
279*2654012fSReza Sabdar static int
bmd_alloc(void)280*2654012fSReza Sabdar bmd_alloc(void)
281*2654012fSReza Sabdar {
282*2654012fSReza Sabdar 	int i;
283*2654012fSReza Sabdar 	bitmap_t *bmp;
284*2654012fSReza Sabdar 
285*2654012fSReza Sabdar 	bmp = bitmap;
286*2654012fSReza Sabdar 	for (i = 0; i < BMAP_MAX; bmp++, i++)
287*2654012fSReza Sabdar 		if (!BMAP_IS_INUSE(bmp)) {
288*2654012fSReza Sabdar 			BMAP_SET_FLAGS(bmp, BMAP_INUSE);
289*2654012fSReza Sabdar 			return (i);
290*2654012fSReza Sabdar 		}
291*2654012fSReza Sabdar 
292*2654012fSReza Sabdar 	return (-1);
293*2654012fSReza Sabdar }
294*2654012fSReza Sabdar 
295*2654012fSReza Sabdar 
296*2654012fSReza Sabdar /*
297*2654012fSReza Sabdar  * bmd_free
298*2654012fSReza Sabdar  *
299*2654012fSReza Sabdar  * Free a bitmap descriptor.  Clears the INUSE flag of the slot.
300*2654012fSReza Sabdar  */
301*2654012fSReza Sabdar static void
bmd_free(int bmd)302*2654012fSReza Sabdar bmd_free(int bmd)
303*2654012fSReza Sabdar {
304*2654012fSReza Sabdar 	bitmap_t *bmp;
305*2654012fSReza Sabdar 
306*2654012fSReza Sabdar 	bmp = bmd2bmp(bmd);
307*2654012fSReza Sabdar 	if (bmp)
308*2654012fSReza Sabdar 		BMAP_UNSET_FLAGS(bmp, BMAP_INUSE);
309*2654012fSReza Sabdar }
310*2654012fSReza Sabdar 
311*2654012fSReza Sabdar 
312*2654012fSReza Sabdar /*
313*2654012fSReza Sabdar  * bmp_set
314*2654012fSReza Sabdar  *
315*2654012fSReza Sabdar  * Generic function to set bit in a chunk.  This can set or unset the
316*2654012fSReza Sabdar  * specified bit.
317*2654012fSReza Sabdar  */
318*2654012fSReza Sabdar static inline int
bmp_set(bmap_chunk_t * cp,u_quad_t bn,uint_t * vp)319*2654012fSReza Sabdar bmp_set(bmap_chunk_t *cp, u_quad_t bn, uint_t *vp)
320*2654012fSReza Sabdar {
321*2654012fSReza Sabdar 	int rv;
322*2654012fSReza Sabdar 	uint_t mask;
323*2654012fSReza Sabdar 	uint_t *ip;
324*2654012fSReza Sabdar 	uint_t v;
325*2654012fSReza Sabdar 
326*2654012fSReza Sabdar 	bn -= cp->c_off;
327*2654012fSReza Sabdar 	if (bn < cp->c_clen) {
328*2654012fSReza Sabdar 		mask = 1 <<(bn & BMAP_BPW_MASK);
329*2654012fSReza Sabdar 		ip = &cp->c_bmp[bn >> BMAP_BPW_SHIFT];
330*2654012fSReza Sabdar 		v = (*vp <<(bn & BMAP_BPW_MASK)) & mask;
331*2654012fSReza Sabdar 		*ip = (*ip & ~mask) | v;
332*2654012fSReza Sabdar 		rv = 0;
333*2654012fSReza Sabdar 	} else
334*2654012fSReza Sabdar 		rv = -ERANGE;
335*2654012fSReza Sabdar 
336*2654012fSReza Sabdar 	return (rv);
337*2654012fSReza Sabdar }
338*2654012fSReza Sabdar 
339*2654012fSReza Sabdar 
340*2654012fSReza Sabdar /*
341*2654012fSReza Sabdar  * bmp_get
342*2654012fSReza Sabdar  *
343*2654012fSReza Sabdar  * Generic function to get bit in a chunk.
344*2654012fSReza Sabdar  */
345*2654012fSReza Sabdar static inline int
bmp_get(bmap_chunk_t * cp,u_quad_t bn)346*2654012fSReza Sabdar bmp_get(bmap_chunk_t *cp, u_quad_t bn)
347*2654012fSReza Sabdar {
348*2654012fSReza Sabdar 	int rv;
349*2654012fSReza Sabdar 	uint_t bit;
350*2654012fSReza Sabdar 
351*2654012fSReza Sabdar 	bn -= cp->c_off;
352*2654012fSReza Sabdar 	if (bn < cp->c_clen) {
353*2654012fSReza Sabdar 		bit = 1 <<(bn & BMAP_BPW_MASK);
354*2654012fSReza Sabdar 		rv = (cp->c_bmp[bn >> BMAP_BPW_SHIFT] & bit) != 0;
355*2654012fSReza Sabdar 	} else
356*2654012fSReza Sabdar 		rv = -ERANGE;
357*2654012fSReza Sabdar 
358*2654012fSReza Sabdar 	return (rv);
359*2654012fSReza Sabdar }
360*2654012fSReza Sabdar 
361*2654012fSReza Sabdar 
362*2654012fSReza Sabdar /*
363*2654012fSReza Sabdar  * bm_chuck_setup
364*2654012fSReza Sabdar  *
365*2654012fSReza Sabdar  * Set up the properties of the new chunk and position it in the hash list.
366*2654012fSReza Sabdar  */
367*2654012fSReza Sabdar static bmap_chunk_t *
bm_chunk_setup(bitmap_t * bmp,bmap_chunk_t * cp,u_quad_t bn)368*2654012fSReza Sabdar bm_chunk_setup(bitmap_t *bmp, bmap_chunk_t *cp, u_quad_t bn)
369*2654012fSReza Sabdar {
370*2654012fSReza Sabdar 	int h;
371*2654012fSReza Sabdar 	u_quad_t off, l;
372*2654012fSReza Sabdar 	uint_t cl, ml;
373*2654012fSReza Sabdar 	bmap_list_t *hp;
374*2654012fSReza Sabdar 
375*2654012fSReza Sabdar 	off = BMAP_CHUNK_OFF(bn);
376*2654012fSReza Sabdar 	l = bmp->bm_len - off;
377*2654012fSReza Sabdar 	if (l >= BMAP_CHUNK_BITS) {
378*2654012fSReza Sabdar 		cl = BMAP_CHUNK_BITS;
379*2654012fSReza Sabdar 		ml = BMAP_CHUNK_BYTES;
380*2654012fSReza Sabdar 	} else {
381*2654012fSReza Sabdar 		cl = l;
382*2654012fSReza Sabdar 		ml = MEM_LEN(l);
383*2654012fSReza Sabdar 	}
384*2654012fSReza Sabdar 
385*2654012fSReza Sabdar 	if (BMAP_IS_INIT_ONES(bmp))
386*2654012fSReza Sabdar 		(void) memset(cp->c_bmp, 0xff, ml);
387*2654012fSReza Sabdar 	else
388*2654012fSReza Sabdar 		(void) memset(cp->c_bmp, 0x00, ml);
389*2654012fSReza Sabdar 
390*2654012fSReza Sabdar 	h = HASH(bn);
391*2654012fSReza Sabdar 	hp = &bmp->bm_hash[h];
392*2654012fSReza Sabdar 
393*2654012fSReza Sabdar 	TAILQ_INSERT_HEAD(hp, cp, c_hash);
394*2654012fSReza Sabdar 	cp->c_off = off;
395*2654012fSReza Sabdar 	cp->c_clen = cl;
396*2654012fSReza Sabdar 	cp->c_mlen = ml;
397*2654012fSReza Sabdar 	return (cp);
398*2654012fSReza Sabdar }
399*2654012fSReza Sabdar 
400*2654012fSReza Sabdar 
401*2654012fSReza Sabdar /*
402*2654012fSReza Sabdar  * bm_chunk_new
403*2654012fSReza Sabdar  *
404*2654012fSReza Sabdar  * Create a new chunk and keep track of memory used.
405*2654012fSReza Sabdar  */
406*2654012fSReza Sabdar static bmap_chunk_t *
bm_chunk_new(bitmap_t * bmp,u_quad_t bn)407*2654012fSReza Sabdar bm_chunk_new(bitmap_t *bmp, u_quad_t bn)
408*2654012fSReza Sabdar {
409*2654012fSReza Sabdar 	bmap_chunk_t *cp;
410*2654012fSReza Sabdar 
411*2654012fSReza Sabdar 	bitmap_stats.bs_chunk_new++;
412*2654012fSReza Sabdar 
413*2654012fSReza Sabdar 	cp = ndmp_malloc(sizeof (bmap_chunk_t));
414*2654012fSReza Sabdar 	if (cp) {
415*2654012fSReza Sabdar 		cp->c_bmp = ndmp_malloc(sizeof (uint_t) * BMAP_CHUNK_WORDS);
416*2654012fSReza Sabdar 		if (!cp->c_bmp) {
417*2654012fSReza Sabdar 			free(cp);
418*2654012fSReza Sabdar 			cp = NULL;
419*2654012fSReza Sabdar 		} else {
420*2654012fSReza Sabdar 			(void) bm_chunk_setup(bmp, cp, bn);
421*2654012fSReza Sabdar 			bmp->bm_ccur++;
422*2654012fSReza Sabdar 		}
423*2654012fSReza Sabdar 	}
424*2654012fSReza Sabdar 
425*2654012fSReza Sabdar 	return (cp);
426*2654012fSReza Sabdar }
427*2654012fSReza Sabdar 
428*2654012fSReza Sabdar 
429*2654012fSReza Sabdar /*
430*2654012fSReza Sabdar  * bm_chunk_alloc
431*2654012fSReza Sabdar  *
432*2654012fSReza Sabdar  * Allocate a chunk and return it.  If the cache for the chunks is not
433*2654012fSReza Sabdar  * fully used, a new chunk is created.
434*2654012fSReza Sabdar  */
435*2654012fSReza Sabdar static bmap_chunk_t *
bm_chunk_alloc(bitmap_t * bmp,u_quad_t bn)436*2654012fSReza Sabdar bm_chunk_alloc(bitmap_t *bmp, u_quad_t bn)
437*2654012fSReza Sabdar {
438*2654012fSReza Sabdar 	bmap_chunk_t *cp;
439*2654012fSReza Sabdar 
440*2654012fSReza Sabdar 	if (bmp->bm_ccur < bmp->bm_cmax)
441*2654012fSReza Sabdar 		cp = bm_chunk_new(bmp, bn);
442*2654012fSReza Sabdar 	else
443*2654012fSReza Sabdar 		cp = NULL;
444*2654012fSReza Sabdar 
445*2654012fSReza Sabdar 	return (cp);
446*2654012fSReza Sabdar }
447*2654012fSReza Sabdar 
448*2654012fSReza Sabdar 
449*2654012fSReza Sabdar /*
450*2654012fSReza Sabdar  * hash_free
451*2654012fSReza Sabdar  *
452*2654012fSReza Sabdar  * Free all chunks on the hash list.
453*2654012fSReza Sabdar  */
454*2654012fSReza Sabdar void
hash_free(bmap_list_t * hp)455*2654012fSReza Sabdar hash_free(bmap_list_t *hp)
456*2654012fSReza Sabdar {
457*2654012fSReza Sabdar 	bmap_chunk_t *cp;
458*2654012fSReza Sabdar 
459*2654012fSReza Sabdar 	if (!hp)
460*2654012fSReza Sabdar 		return;
461*2654012fSReza Sabdar 
462*2654012fSReza Sabdar 	while (!TAILQ_EMPTY(hp)) {
463*2654012fSReza Sabdar 		cp = TAILQ_FIRST(hp);
464*2654012fSReza Sabdar 		TAILQ_REMOVE(hp, cp, c_hash);
465*2654012fSReza Sabdar 		free(cp->c_bmp);
466*2654012fSReza Sabdar 		free(cp);
467*2654012fSReza Sabdar 	}
468*2654012fSReza Sabdar }
469*2654012fSReza Sabdar 
470*2654012fSReza Sabdar 
471*2654012fSReza Sabdar /*
472*2654012fSReza Sabdar  * bm_chunks_free
473*2654012fSReza Sabdar  *
474*2654012fSReza Sabdar  * Release the memory allocated for the chunks.
475*2654012fSReza Sabdar  */
476*2654012fSReza Sabdar static void
bm_chunks_free(bmap_list_t * hp)477*2654012fSReza Sabdar bm_chunks_free(bmap_list_t *hp)
478*2654012fSReza Sabdar {
479*2654012fSReza Sabdar 	int i;
480*2654012fSReza Sabdar 
481*2654012fSReza Sabdar 	for (i = 0; i < BMAP_HASH_SIZE; hp++, i++)
482*2654012fSReza Sabdar 		hash_free(hp);
483*2654012fSReza Sabdar }
484*2654012fSReza Sabdar 
485*2654012fSReza Sabdar 
486*2654012fSReza Sabdar /*
487*2654012fSReza Sabdar  * bm_chunk_repositions
488*2654012fSReza Sabdar  *
489*2654012fSReza Sabdar  * Re-position the chunk in the MRU hash table.
490*2654012fSReza Sabdar  */
491*2654012fSReza Sabdar static void
bm_chunk_reposition(bitmap_t * bmp,bmap_list_t * hp,bmap_chunk_t * cp)492*2654012fSReza Sabdar bm_chunk_reposition(bitmap_t *bmp, bmap_list_t *hp, bmap_chunk_t *cp)
493*2654012fSReza Sabdar {
494*2654012fSReza Sabdar 	if (!bmp || !hp || !cp)
495*2654012fSReza Sabdar 		return;
496*2654012fSReza Sabdar 
497*2654012fSReza Sabdar 	if (TAILQ_FIRST(hp) != cp) {
498*2654012fSReza Sabdar 		TAILQ_REMOVE(hp, cp, c_hash);
499*2654012fSReza Sabdar 		TAILQ_INSERT_HEAD(hp, cp, c_hash);
500*2654012fSReza Sabdar 	}
501*2654012fSReza Sabdar }
502*2654012fSReza Sabdar 
503*2654012fSReza Sabdar 
504*2654012fSReza Sabdar /*
505*2654012fSReza Sabdar  * bm_chunk_find
506*2654012fSReza Sabdar  *
507*2654012fSReza Sabdar  * Find and return the chunks which holds the specified bit. Allocate
508*2654012fSReza Sabdar  * the chunk if necessary and re-position it in the hash table lists.
509*2654012fSReza Sabdar  */
510*2654012fSReza Sabdar static bmap_chunk_t *
bm_chunk_find(bitmap_t * bmp,u_quad_t bn)511*2654012fSReza Sabdar bm_chunk_find(bitmap_t *bmp, u_quad_t bn)
512*2654012fSReza Sabdar {
513*2654012fSReza Sabdar 	int h;
514*2654012fSReza Sabdar 	bmap_chunk_t *cp;
515*2654012fSReza Sabdar 	bmap_list_t *hp;
516*2654012fSReza Sabdar 
517*2654012fSReza Sabdar 	if (!bmp)
518*2654012fSReza Sabdar 		return (NULL);
519*2654012fSReza Sabdar 
520*2654012fSReza Sabdar 	h = HASH(bn);
521*2654012fSReza Sabdar 	hp = &bmp->bm_hash[h];
522*2654012fSReza Sabdar 	TAILQ_FOREACH(cp, hp, c_hash) {
523*2654012fSReza Sabdar 		if (bn >= cp->c_off && bn < (cp->c_off + cp->c_clen)) {
524*2654012fSReza Sabdar 			bitmap_stats.bs_cache_hit++;
525*2654012fSReza Sabdar 
526*2654012fSReza Sabdar 			bm_chunk_reposition(bmp, hp, cp);
527*2654012fSReza Sabdar 			return (cp);
528*2654012fSReza Sabdar 		}
529*2654012fSReza Sabdar 	}
530*2654012fSReza Sabdar 
531*2654012fSReza Sabdar 	bitmap_stats.bs_cache_miss++;
532*2654012fSReza Sabdar 
533*2654012fSReza Sabdar 	return (bm_chunk_alloc(bmp, bn));
534*2654012fSReza Sabdar }
535*2654012fSReza Sabdar 
536*2654012fSReza Sabdar 
537*2654012fSReza Sabdar /*
538*2654012fSReza Sabdar  * bmp_setval
539*2654012fSReza Sabdar  *
540*2654012fSReza Sabdar  * Set a range of bits in the bitmap specified by the vector.
541*2654012fSReza Sabdar  */
542*2654012fSReza Sabdar static int
bmp_setval(bitmap_t * bmp,bm_iovec_t * vp)543*2654012fSReza Sabdar bmp_setval(bitmap_t *bmp, bm_iovec_t *vp)
544*2654012fSReza Sabdar {
545*2654012fSReza Sabdar 	int rv;
546*2654012fSReza Sabdar 	u_quad_t cl;
547*2654012fSReza Sabdar 	u_quad_t bn;
548*2654012fSReza Sabdar 	u_quad_t max;
549*2654012fSReza Sabdar 	bmap_chunk_t *cp;
550*2654012fSReza Sabdar 
551*2654012fSReza Sabdar 	bn = vp->bmv_base;
552*2654012fSReza Sabdar 	max = bn + vp->bmv_len;
553*2654012fSReza Sabdar 	if (bn >= bmp->bm_len || max > bmp->bm_len)
554*2654012fSReza Sabdar 		return (-EINVAL);
555*2654012fSReza Sabdar 
556*2654012fSReza Sabdar 	if (*vp->bmv_val) {
557*2654012fSReza Sabdar 		bitmap_stats.bs_set++;
558*2654012fSReza Sabdar 		bitmap_stats.bs_set_bits += vp->bmv_len;
559*2654012fSReza Sabdar 	} else {
560*2654012fSReza Sabdar 		bitmap_stats.bs_unset++;
561*2654012fSReza Sabdar 		bitmap_stats.bs_unset_bits += vp->bmv_len;
562*2654012fSReza Sabdar 	}
563*2654012fSReza Sabdar 
564*2654012fSReza Sabdar 	do {
565*2654012fSReza Sabdar 		cp = bm_chunk_find(bmp, bn);
566*2654012fSReza Sabdar 		if (!cp)
567*2654012fSReza Sabdar 			return (-ERANGE);
568*2654012fSReza Sabdar 
569*2654012fSReza Sabdar 		for (cl = cp->c_off + cp->c_clen; bn < cl && bn < max; bn++) {
570*2654012fSReza Sabdar 			rv = bmp_set(cp, bn, vp->bmv_val);
571*2654012fSReza Sabdar 			if (rv != 0)
572*2654012fSReza Sabdar 				return (rv);
573*2654012fSReza Sabdar 		}
574*2654012fSReza Sabdar 	} while (bn < max);
575*2654012fSReza Sabdar 
576*2654012fSReza Sabdar 	return (0);
577*2654012fSReza Sabdar }
578*2654012fSReza Sabdar 
579*2654012fSReza Sabdar 
580*2654012fSReza Sabdar /*
581*2654012fSReza Sabdar  * bmp_getval
582*2654012fSReza Sabdar  *
583*2654012fSReza Sabdar  * Get a range of bits in the bitmap specified by the vector.
584*2654012fSReza Sabdar  */
585*2654012fSReza Sabdar static int
bmp_getval(bitmap_t * bmp,bm_iovec_t * vp)586*2654012fSReza Sabdar bmp_getval(bitmap_t *bmp, bm_iovec_t *vp)
587*2654012fSReza Sabdar {
588*2654012fSReza Sabdar 	uint_t cnt;
589*2654012fSReza Sabdar 	uint_t *ip;
590*2654012fSReza Sabdar 	int rv;
591*2654012fSReza Sabdar 	u_quad_t cl;
592*2654012fSReza Sabdar 	u_quad_t bn;
593*2654012fSReza Sabdar 	u_quad_t max;
594*2654012fSReza Sabdar 	bmap_chunk_t *cp;
595*2654012fSReza Sabdar 
596*2654012fSReza Sabdar 	bn = vp->bmv_base;
597*2654012fSReza Sabdar 	max = bn + vp->bmv_len;
598*2654012fSReza Sabdar 	if (bn >= bmp->bm_len || max > bmp->bm_len)
599*2654012fSReza Sabdar 		return (-EINVAL);
600*2654012fSReza Sabdar 
601*2654012fSReza Sabdar 	bitmap_stats.bs_get++;
602*2654012fSReza Sabdar 	bitmap_stats.bs_get_bits += 1;
603*2654012fSReza Sabdar 
604*2654012fSReza Sabdar 	cnt = 0;
605*2654012fSReza Sabdar 	ip = vp->bmv_val;
606*2654012fSReza Sabdar 	*ip = 0;
607*2654012fSReza Sabdar 	do {
608*2654012fSReza Sabdar 		cp = bm_chunk_find(bmp, bn);
609*2654012fSReza Sabdar 		if (!cp)
610*2654012fSReza Sabdar 			return (-ERANGE);
611*2654012fSReza Sabdar 
612*2654012fSReza Sabdar 		for (cl = cp->c_off + cp->c_clen; bn < cl && bn < max; bn++) {
613*2654012fSReza Sabdar 			rv = bmp_get(cp, bn);
614*2654012fSReza Sabdar 			if (rv < 0)
615*2654012fSReza Sabdar 				return (rv);
616*2654012fSReza Sabdar 
617*2654012fSReza Sabdar 			*ip |= rv << cnt;
618*2654012fSReza Sabdar 			if (++cnt >= BMAP_BPW) {
619*2654012fSReza Sabdar 				*++ip = 0;
620*2654012fSReza Sabdar 				cnt = 0;
621*2654012fSReza Sabdar 			}
622*2654012fSReza Sabdar 		}
623*2654012fSReza Sabdar 	} while (bn < max);
624*2654012fSReza Sabdar 
625*2654012fSReza Sabdar 	return (0);
626*2654012fSReza Sabdar }
627*2654012fSReza Sabdar 
628*2654012fSReza Sabdar 
629*2654012fSReza Sabdar /*
630*2654012fSReza Sabdar  * hash_init
631*2654012fSReza Sabdar  *
632*2654012fSReza Sabdar  * Initialize the hash table lists head.
633*2654012fSReza Sabdar  */
634*2654012fSReza Sabdar static void
hash_init(bmap_list_t * hp)635*2654012fSReza Sabdar hash_init(bmap_list_t *hp)
636*2654012fSReza Sabdar {
637*2654012fSReza Sabdar 	int i;
638*2654012fSReza Sabdar 
639*2654012fSReza Sabdar 	for (i = 0; i < BMAP_HASH_SIZE; hp++, i++) {
640*2654012fSReza Sabdar 		TAILQ_INIT(hp);
641*2654012fSReza Sabdar 	}
642*2654012fSReza Sabdar }
643*2654012fSReza Sabdar 
644*2654012fSReza Sabdar 
645*2654012fSReza Sabdar /*
646*2654012fSReza Sabdar  * bm_alloc
647*2654012fSReza Sabdar  *
648*2654012fSReza Sabdar  * Allocate a bit map and return a handle to it.
649*2654012fSReza Sabdar  *
650*2654012fSReza Sabdar  * The hash table list are empty at this point. They are allocated
651*2654012fSReza Sabdar  * on demand.
652*2654012fSReza Sabdar  */
653*2654012fSReza Sabdar int
bm_alloc(u_quad_t len,int set)654*2654012fSReza Sabdar bm_alloc(u_quad_t len, int set)
655*2654012fSReza Sabdar {
656*2654012fSReza Sabdar 	int bmd;
657*2654012fSReza Sabdar 	bitmap_t *bmp;
658*2654012fSReza Sabdar 
659*2654012fSReza Sabdar 	if (len == 0)
660*2654012fSReza Sabdar 		return (-1);
661*2654012fSReza Sabdar 
662*2654012fSReza Sabdar 	bmd = bmd_alloc();
663*2654012fSReza Sabdar 	if (bmd < 0)
664*2654012fSReza Sabdar 		return (bmd);
665*2654012fSReza Sabdar 
666*2654012fSReza Sabdar 	bmp = bmd2bmp(bmd);
667*2654012fSReza Sabdar 	bitmap_stats.bs_alloc_cnt++;
668*2654012fSReza Sabdar 	bitmap_stats.bs_alloc_size += len;
669*2654012fSReza Sabdar 
670*2654012fSReza Sabdar 	if (set)
671*2654012fSReza Sabdar 		BMAP_SET_FLAGS(bmp, BMAP_BINIT_ONES);
672*2654012fSReza Sabdar 	else
673*2654012fSReza Sabdar 		BMAP_UNSET_FLAGS(bmp, BMAP_BINIT_ONES);
674*2654012fSReza Sabdar 	bmp->bm_len = len;
675*2654012fSReza Sabdar 	bmp->bm_ccur = 0;
676*2654012fSReza Sabdar 	bmp->bm_cmax = BMAP_CHUNK_MAX;
677*2654012fSReza Sabdar 	hash_init(bmp->bm_hash);
678*2654012fSReza Sabdar 
679*2654012fSReza Sabdar 	return (bmd);
680*2654012fSReza Sabdar }
681*2654012fSReza Sabdar 
682*2654012fSReza Sabdar 
683*2654012fSReza Sabdar /*
684*2654012fSReza Sabdar  * bm_free
685*2654012fSReza Sabdar  *
686*2654012fSReza Sabdar  * Free memory allocated for the bitmap.
687*2654012fSReza Sabdar  */
688*2654012fSReza Sabdar int
bm_free(int bmd)689*2654012fSReza Sabdar bm_free(int bmd)
690*2654012fSReza Sabdar {
691*2654012fSReza Sabdar 	int rv;
692*2654012fSReza Sabdar 	bitmap_t *bmp;
693*2654012fSReza Sabdar 
694*2654012fSReza Sabdar 	bmp = bmd2bmp(bmd);
695*2654012fSReza Sabdar 	if (bmp && BMAP_IS_INUSE(bmp)) {
696*2654012fSReza Sabdar 		bitmap_stats.bs_free_cnt++;
697*2654012fSReza Sabdar 
698*2654012fSReza Sabdar 		bm_chunks_free(bmp->bm_hash);
699*2654012fSReza Sabdar 		bmd_free(bmd);
700*2654012fSReza Sabdar 		rv = 0;
701*2654012fSReza Sabdar 	} else
702*2654012fSReza Sabdar 		rv = -1;
703*2654012fSReza Sabdar 
704*2654012fSReza Sabdar 	return (rv);
705*2654012fSReza Sabdar }
706*2654012fSReza Sabdar 
707*2654012fSReza Sabdar 
708*2654012fSReza Sabdar /*
709*2654012fSReza Sabdar  * bm_getiov
710*2654012fSReza Sabdar  *
711*2654012fSReza Sabdar  * Get bits specified by the array of vectors.
712*2654012fSReza Sabdar  */
713*2654012fSReza Sabdar int
bm_getiov(int bmd,bm_io_t * iop)714*2654012fSReza Sabdar bm_getiov(int bmd, bm_io_t *iop)
715*2654012fSReza Sabdar {
716*2654012fSReza Sabdar 	int i;
717*2654012fSReza Sabdar 	int rv;
718*2654012fSReza Sabdar 	bm_iovec_t *vp;
719*2654012fSReza Sabdar 	bitmap_t *bmp;
720*2654012fSReza Sabdar 
721*2654012fSReza Sabdar 	if (!iop)
722*2654012fSReza Sabdar 		rv = -EINVAL;
723*2654012fSReza Sabdar 	else if (!(bmp = bmd2bmp(bmd)))
724*2654012fSReza Sabdar 		rv = -EINVAL;
725*2654012fSReza Sabdar 	else if (iop->bmio_iovcnt <= 0)
726*2654012fSReza Sabdar 		rv = -EINVAL;
727*2654012fSReza Sabdar 	else {
728*2654012fSReza Sabdar 		rv = 0;
729*2654012fSReza Sabdar 		vp = iop->bmio_iov;
730*2654012fSReza Sabdar 		for (i = 0; i < iop->bmio_iovcnt; vp++, i++) {
731*2654012fSReza Sabdar 			if (!vp)
732*2654012fSReza Sabdar 				return (-EINVAL);
733*2654012fSReza Sabdar 			rv |= bmp_getval(bmp, vp);
734*2654012fSReza Sabdar 		}
735*2654012fSReza Sabdar 	}
736*2654012fSReza Sabdar 
737*2654012fSReza Sabdar 	return (rv);
738*2654012fSReza Sabdar }
739*2654012fSReza Sabdar 
740*2654012fSReza Sabdar 
741*2654012fSReza Sabdar /*
742*2654012fSReza Sabdar  * bm_setiov
743*2654012fSReza Sabdar  *
744*2654012fSReza Sabdar  * Set bits specified by the array of vectors.
745*2654012fSReza Sabdar  */
746*2654012fSReza Sabdar int
bm_setiov(int bmd,bm_io_t * iop)747*2654012fSReza Sabdar bm_setiov(int bmd, bm_io_t *iop)
748*2654012fSReza Sabdar {
749*2654012fSReza Sabdar 	int i;
750*2654012fSReza Sabdar 	int rv;
751*2654012fSReza Sabdar 	bm_iovec_t *vp;
752*2654012fSReza Sabdar 	bitmap_t *bmp;
753*2654012fSReza Sabdar 
754*2654012fSReza Sabdar 	if (!iop)
755*2654012fSReza Sabdar 		rv = -EINVAL;
756*2654012fSReza Sabdar 	else if (!(bmp = bmd2bmp(bmd)))
757*2654012fSReza Sabdar 		rv = -EINVAL;
758*2654012fSReza Sabdar 	else if (iop->bmio_iovcnt <= 0)
759*2654012fSReza Sabdar 		rv = -EINVAL;
760*2654012fSReza Sabdar 	else if (!iop->bmio_iov)
761*2654012fSReza Sabdar 		rv = -EINVAL;
762*2654012fSReza Sabdar 	else {
763*2654012fSReza Sabdar 		rv = 0;
764*2654012fSReza Sabdar 		vp = iop->bmio_iov;
765*2654012fSReza Sabdar 		for (i = 0; i < iop->bmio_iovcnt; vp++, i++)
766*2654012fSReza Sabdar 			rv |= bmp_setval(bmp, vp);
767*2654012fSReza Sabdar 	}
768*2654012fSReza Sabdar 
769*2654012fSReza Sabdar 	return (rv);
770*2654012fSReza Sabdar }
771*2654012fSReza Sabdar 
772*2654012fSReza Sabdar 
773*2654012fSReza Sabdar /*
774*2654012fSReza Sabdar  * bmd2dbmp
775*2654012fSReza Sabdar  *
776*2654012fSReza Sabdar  * Convert bitmap descriptor to bitmap pointer.
777*2654012fSReza Sabdar  */
778*2654012fSReza Sabdar static dbitmap_t *
bmd2dbmp(int bmd)779*2654012fSReza Sabdar bmd2dbmp(int bmd)
780*2654012fSReza Sabdar {
781*2654012fSReza Sabdar 	if (bmd < 0 || bmd >= BMAP_MAX)
782*2654012fSReza Sabdar 		return (NULL);
783*2654012fSReza Sabdar 
784*2654012fSReza Sabdar 	return (&dbitmap[bmd]);
785*2654012fSReza Sabdar }
786*2654012fSReza Sabdar 
787*2654012fSReza Sabdar 
788*2654012fSReza Sabdar /*
789*2654012fSReza Sabdar  * dbmp2bmd
790*2654012fSReza Sabdar  *
791*2654012fSReza Sabdar  * Convert bitmap pointer to bitmap descriptor.
792*2654012fSReza Sabdar  */
793*2654012fSReza Sabdar static int
dbmp2bmd(dbitmap_t * bmp)794*2654012fSReza Sabdar dbmp2bmd(dbitmap_t *bmp)
795*2654012fSReza Sabdar {
796*2654012fSReza Sabdar 	int bmd;
797*2654012fSReza Sabdar 
798*2654012fSReza Sabdar 	bmd = bmp - dbitmap;
799*2654012fSReza Sabdar 	if (bmd < 0 || bmd >= BMAP_MAX)
800*2654012fSReza Sabdar 		bmd = -1;
801*2654012fSReza Sabdar 
802*2654012fSReza Sabdar 	return (bmd);
803*2654012fSReza Sabdar }
804*2654012fSReza Sabdar 
805*2654012fSReza Sabdar /*
806*2654012fSReza Sabdar  * dbmd_alloc
807*2654012fSReza Sabdar  *
808*2654012fSReza Sabdar  * Allocate a bitmap descriptor.
809*2654012fSReza Sabdar  * Sets the INUSE flag of the slot.
810*2654012fSReza Sabdar  */
811*2654012fSReza Sabdar static int
dbmd_alloc(void)812*2654012fSReza Sabdar dbmd_alloc(void)
813*2654012fSReza Sabdar {
814*2654012fSReza Sabdar 	int i;
815*2654012fSReza Sabdar 	dbitmap_t *bmp;
816*2654012fSReza Sabdar 
817*2654012fSReza Sabdar 	bmp = dbitmap;
818*2654012fSReza Sabdar 	for (i = 0; i < BMAP_MAX; bmp++, i++)
819*2654012fSReza Sabdar 		if (!BMAP_IS_INUSE(bmp)) {
820*2654012fSReza Sabdar 			BMAP_SET_FLAGS(bmp, BMAP_INUSE);
821*2654012fSReza Sabdar 			return (i);
822*2654012fSReza Sabdar 		}
823*2654012fSReza Sabdar 
824*2654012fSReza Sabdar 	return (-1);
825*2654012fSReza Sabdar }
826*2654012fSReza Sabdar 
827*2654012fSReza Sabdar 
828*2654012fSReza Sabdar /*
829*2654012fSReza Sabdar  * dbmd_free
830*2654012fSReza Sabdar  *
831*2654012fSReza Sabdar  * Free a bitmap descriptor.
832*2654012fSReza Sabdar  * Clears the INUSE flag of the slot.
833*2654012fSReza Sabdar  */
834*2654012fSReza Sabdar static void
dbmd_free(int bmd)835*2654012fSReza Sabdar dbmd_free(int bmd)
836*2654012fSReza Sabdar {
837*2654012fSReza Sabdar 	dbitmap_t *bmp;
838*2654012fSReza Sabdar 
839*2654012fSReza Sabdar 	bmp = bmd2dbmp(bmd);
840*2654012fSReza Sabdar 	if (bmp)
841*2654012fSReza Sabdar 		BMAP_UNSET_FLAGS(bmp, BMAP_INUSE);
842*2654012fSReza Sabdar }
843*2654012fSReza Sabdar 
844*2654012fSReza Sabdar 
845*2654012fSReza Sabdar /*
846*2654012fSReza Sabdar  * dbmp_set
847*2654012fSReza Sabdar  *
848*2654012fSReza Sabdar  * Generic function to set bit in a chunk.  This can
849*2654012fSReza Sabdar  * set or unset the specified bit.
850*2654012fSReza Sabdar  */
851*2654012fSReza Sabdar static inline int
dbmp_set(dbmap_chunk_t * cp,u_quad_t bn,uint_t * vp)852*2654012fSReza Sabdar dbmp_set(dbmap_chunk_t *cp, u_quad_t bn, uint_t *vp)
853*2654012fSReza Sabdar {
854*2654012fSReza Sabdar 	int rv;
855*2654012fSReza Sabdar 	uint_t mask;
856*2654012fSReza Sabdar 	uint_t *ip;
857*2654012fSReza Sabdar 	uint_t v;
858*2654012fSReza Sabdar 
859*2654012fSReza Sabdar 	bn -= cp->c_off;
860*2654012fSReza Sabdar 	if (bn < cp->c_clen) {
861*2654012fSReza Sabdar 		mask = 1 <<(bn & BMAP_BPW_MASK);
862*2654012fSReza Sabdar 		ip = &cp->c_bmp[bn >> BMAP_BPW_SHIFT];
863*2654012fSReza Sabdar 		v = (*vp <<(bn & BMAP_BPW_MASK)) & mask;
864*2654012fSReza Sabdar 		*ip = (*ip & ~mask) | v;
865*2654012fSReza Sabdar 		BMAP_CSET_DIRTY(cp);
866*2654012fSReza Sabdar 		rv = 0;
867*2654012fSReza Sabdar 	} else
868*2654012fSReza Sabdar 		rv = -ERANGE;
869*2654012fSReza Sabdar 
870*2654012fSReza Sabdar 	return (rv);
871*2654012fSReza Sabdar }
872*2654012fSReza Sabdar 
873*2654012fSReza Sabdar 
874*2654012fSReza Sabdar /*
875*2654012fSReza Sabdar  * dbmp_getlen
876*2654012fSReza Sabdar  *
877*2654012fSReza Sabdar  * Get length of the bitmap.
878*2654012fSReza Sabdar  */
879*2654012fSReza Sabdar static u_quad_t
dbmp_getlen(dbitmap_t * bmp)880*2654012fSReza Sabdar dbmp_getlen(dbitmap_t *bmp)
881*2654012fSReza Sabdar {
882*2654012fSReza Sabdar 	return (bmp ? bmp->bm_len : 0LL);
883*2654012fSReza Sabdar }
884*2654012fSReza Sabdar 
885*2654012fSReza Sabdar 
886*2654012fSReza Sabdar /*
887*2654012fSReza Sabdar  * dbmp_get
888*2654012fSReza Sabdar  *
889*2654012fSReza Sabdar  * Generic function to get bit in a chunk.
890*2654012fSReza Sabdar  */
891*2654012fSReza Sabdar static inline int
dbmp_get(dbmap_chunk_t * cp,u_quad_t bn)892*2654012fSReza Sabdar dbmp_get(dbmap_chunk_t *cp, u_quad_t bn)
893*2654012fSReza Sabdar {
894*2654012fSReza Sabdar 	int rv;
895*2654012fSReza Sabdar 	uint_t bit;
896*2654012fSReza Sabdar 
897*2654012fSReza Sabdar 	bn -= cp->c_off;
898*2654012fSReza Sabdar 	if (bn < cp->c_clen) {
899*2654012fSReza Sabdar 		bit = 1 <<(bn & BMAP_BPW_MASK);
900*2654012fSReza Sabdar 		rv = (cp->c_bmp[bn >> BMAP_BPW_SHIFT] & bit) != 0;
901*2654012fSReza Sabdar 	} else
902*2654012fSReza Sabdar 		rv = -ERANGE;
903*2654012fSReza Sabdar 
904*2654012fSReza Sabdar 	return (rv);
905*2654012fSReza Sabdar }
906*2654012fSReza Sabdar 
907*2654012fSReza Sabdar 
908*2654012fSReza Sabdar /*
909*2654012fSReza Sabdar  * dbm_chunk_seek
910*2654012fSReza Sabdar  *
911*2654012fSReza Sabdar  * Seek in the file where the chunk is saved or should be saved.
912*2654012fSReza Sabdar  */
913*2654012fSReza Sabdar static int
dbm_chunk_seek(dbitmap_t * bmp,u_quad_t bn)914*2654012fSReza Sabdar dbm_chunk_seek(dbitmap_t *bmp, u_quad_t bn)
915*2654012fSReza Sabdar {
916*2654012fSReza Sabdar 	int rv;
917*2654012fSReza Sabdar 	off_t off;
918*2654012fSReza Sabdar 
919*2654012fSReza Sabdar 	if (!bmp)
920*2654012fSReza Sabdar 		rv = -1;
921*2654012fSReza Sabdar 	else {
922*2654012fSReza Sabdar 		off = BMAP_CHUNK_NO(bn) * BMAP_CHUNK_BYTES;
923*2654012fSReza Sabdar 		rv = (lseek(bmp->bm_fd, off, SEEK_SET) != off) ? -1 : 0;
924*2654012fSReza Sabdar 	}
925*2654012fSReza Sabdar 
926*2654012fSReza Sabdar 	return (rv);
927*2654012fSReza Sabdar }
928*2654012fSReza Sabdar 
929*2654012fSReza Sabdar 
930*2654012fSReza Sabdar /*
931*2654012fSReza Sabdar  * dbm_chunk_flush
932*2654012fSReza Sabdar  *
933*2654012fSReza Sabdar  * Save a chunk to file.
934*2654012fSReza Sabdar  */
935*2654012fSReza Sabdar static int
dbm_chunk_flush(dbitmap_t * bmp,dbmap_chunk_t * cp)936*2654012fSReza Sabdar dbm_chunk_flush(dbitmap_t *bmp, dbmap_chunk_t *cp)
937*2654012fSReza Sabdar {
938*2654012fSReza Sabdar 	int rv;
939*2654012fSReza Sabdar 
940*2654012fSReza Sabdar 	bitmap_stats.bs_chunk_flush++;
941*2654012fSReza Sabdar 	if (!bmp || !cp)
942*2654012fSReza Sabdar 		rv = -1;
943*2654012fSReza Sabdar 	else if (dbm_chunk_seek(bmp, cp->c_off) != 0)
944*2654012fSReza Sabdar 		rv = -1;
945*2654012fSReza Sabdar 	else if (write(bmp->bm_fd, cp->c_bmp, cp->c_mlen) != cp->c_mlen)
946*2654012fSReza Sabdar 		rv = -1;
947*2654012fSReza Sabdar 	else
948*2654012fSReza Sabdar 		rv = 0;
949*2654012fSReza Sabdar 
950*2654012fSReza Sabdar 	return (rv);
951*2654012fSReza Sabdar }
952*2654012fSReza Sabdar 
953*2654012fSReza Sabdar 
954*2654012fSReza Sabdar /*
955*2654012fSReza Sabdar  * dbm_chunk_load
956*2654012fSReza Sabdar  *
957*2654012fSReza Sabdar  * Load a chunk from a file.  If the chunk is a new one,
958*2654012fSReza Sabdar  * instead of reading from the disk, the memory for the
959*2654012fSReza Sabdar  * chunk is set to either all zeros or to all ones.
960*2654012fSReza Sabdar  * Otherwise, if the chunk is not a new one, it's read
961*2654012fSReza Sabdar  * from the disk.
962*2654012fSReza Sabdar  *
963*2654012fSReza Sabdar  * The new chunk is positioned in the LRU and hash table
964*2654012fSReza Sabdar  * after its data is ready.
965*2654012fSReza Sabdar  */
966*2654012fSReza Sabdar static dbmap_chunk_t *
dbm_chunk_load(dbitmap_t * bmp,dbmap_chunk_t * cp,u_quad_t bn,int new)967*2654012fSReza Sabdar dbm_chunk_load(dbitmap_t *bmp, dbmap_chunk_t *cp, u_quad_t bn, int new)
968*2654012fSReza Sabdar {
969*2654012fSReza Sabdar 	int h;
970*2654012fSReza Sabdar 	u_quad_t off, l;
971*2654012fSReza Sabdar 	uint_t cl, ml;
972*2654012fSReza Sabdar 	dbmap_list_t *hp;
973*2654012fSReza Sabdar 
974*2654012fSReza Sabdar 	off = BMAP_CHUNK_OFF(bn);
975*2654012fSReza Sabdar 	l = bmp->bm_len - off;
976*2654012fSReza Sabdar 	if (l >= BMAP_CHUNK_BITS) {
977*2654012fSReza Sabdar 		cl = BMAP_CHUNK_BITS;
978*2654012fSReza Sabdar 		ml = BMAP_CHUNK_BYTES;
979*2654012fSReza Sabdar 	} else {
980*2654012fSReza Sabdar 		cl = l;
981*2654012fSReza Sabdar 		ml = MEM_LEN(l);
982*2654012fSReza Sabdar 	}
983*2654012fSReza Sabdar 
984*2654012fSReza Sabdar 	if (new == BMAP_NEW_CHUNK) {
985*2654012fSReza Sabdar 		if (BMAP_IS_INIT_ONES(bmp))
986*2654012fSReza Sabdar 			(void) memset(cp->c_bmp, 0xff, ml);
987*2654012fSReza Sabdar 		else
988*2654012fSReza Sabdar 			(void) memset(cp->c_bmp, 0x00, ml);
989*2654012fSReza Sabdar 	} else { /* BMAP_OLD_CHUNK */
990*2654012fSReza Sabdar 		if (dbm_chunk_seek(bmp, bn) != 0)
991*2654012fSReza Sabdar 			cp = NULL;
992*2654012fSReza Sabdar 		else if (read(bmp->bm_fd, cp->c_bmp, ml) != ml)
993*2654012fSReza Sabdar 			cp = NULL;
994*2654012fSReza Sabdar 	}
995*2654012fSReza Sabdar 
996*2654012fSReza Sabdar 	if (cp) {
997*2654012fSReza Sabdar 		TAILQ_INSERT_TAIL(&bmp->bm_lru, cp, c_lru);
998*2654012fSReza Sabdar 		h = HASH(bn);
999*2654012fSReza Sabdar 		hp = &bmp->bm_hash[h];
1000*2654012fSReza Sabdar 		TAILQ_INSERT_HEAD(hp, cp, c_hash);
1001*2654012fSReza Sabdar 		cp->c_flags = 0;
1002*2654012fSReza Sabdar 		cp->c_off = off;
1003*2654012fSReza Sabdar 		cp->c_clen = cl;
1004*2654012fSReza Sabdar 		cp->c_mlen = ml;
1005*2654012fSReza Sabdar 	}
1006*2654012fSReza Sabdar 
1007*2654012fSReza Sabdar 	return (cp);
1008*2654012fSReza Sabdar }
1009*2654012fSReza Sabdar 
1010*2654012fSReza Sabdar 
1011*2654012fSReza Sabdar /*
1012*2654012fSReza Sabdar  * dbm_chunk_new
1013*2654012fSReza Sabdar  *
1014*2654012fSReza Sabdar  * Create a new chunk and keep track of memory used.
1015*2654012fSReza Sabdar  */
1016*2654012fSReza Sabdar static dbmap_chunk_t *
dbm_chunk_new(dbitmap_t * bmp,u_quad_t bn)1017*2654012fSReza Sabdar dbm_chunk_new(dbitmap_t *bmp, u_quad_t bn)
1018*2654012fSReza Sabdar {
1019*2654012fSReza Sabdar 	dbmap_chunk_t *cp;
1020*2654012fSReza Sabdar 
1021*2654012fSReza Sabdar 	bitmap_stats.bs_chunk_new++;
1022*2654012fSReza Sabdar 	cp = ndmp_malloc(sizeof (dbmap_chunk_t));
1023*2654012fSReza Sabdar 	if (cp) {
1024*2654012fSReza Sabdar 		cp->c_bmp = ndmp_malloc(sizeof (uint_t) * BMAP_CHUNK_WORDS);
1025*2654012fSReza Sabdar 		if (!cp->c_bmp) {
1026*2654012fSReza Sabdar 			free(cp);
1027*2654012fSReza Sabdar 			cp = NULL;
1028*2654012fSReza Sabdar 		} else if (!dbm_chunk_load(bmp, cp, bn, BMAP_NEW_CHUNK)) {
1029*2654012fSReza Sabdar 			free(cp->c_bmp);
1030*2654012fSReza Sabdar 			free(cp);
1031*2654012fSReza Sabdar 			cp = NULL;
1032*2654012fSReza Sabdar 		} else
1033*2654012fSReza Sabdar 			bmp->bm_ccur++;
1034*2654012fSReza Sabdar 	}
1035*2654012fSReza Sabdar 
1036*2654012fSReza Sabdar 	return (cp);
1037*2654012fSReza Sabdar }
1038*2654012fSReza Sabdar 
1039*2654012fSReza Sabdar 
1040*2654012fSReza Sabdar /*
1041*2654012fSReza Sabdar  * dbm_chunk_alloc
1042*2654012fSReza Sabdar  *
1043*2654012fSReza Sabdar  * Allocate a chunk and return it.  If the cache for the
1044*2654012fSReza Sabdar  * chunks is not fully used, a new chunk is created.
1045*2654012fSReza Sabdar  * Otherwise, the first chunk from the LRU list is reclaimed,
1046*2654012fSReza Sabdar  * loaded and returned.
1047*2654012fSReza Sabdar  */
1048*2654012fSReza Sabdar static dbmap_chunk_t *
dbm_chunk_alloc(dbitmap_t * bmp,u_quad_t bn)1049*2654012fSReza Sabdar dbm_chunk_alloc(dbitmap_t *bmp, u_quad_t bn)
1050*2654012fSReza Sabdar {
1051*2654012fSReza Sabdar 	int h;
1052*2654012fSReza Sabdar 	dbmap_list_t *hp;
1053*2654012fSReza Sabdar 	dbmap_chunk_t *cp;
1054*2654012fSReza Sabdar 
1055*2654012fSReza Sabdar 	if (bmp->bm_ccur < bmp->bm_cmax)
1056*2654012fSReza Sabdar 		return (dbm_chunk_new(bmp, bn));
1057*2654012fSReza Sabdar 
1058*2654012fSReza Sabdar 	bitmap_stats.bs_chunk_reclaim++;
1059*2654012fSReza Sabdar 
1060*2654012fSReza Sabdar 	cp = TAILQ_FIRST(&bmp->bm_lru);
1061*2654012fSReza Sabdar 	if (BMAP_CIS_DIRTY(cp))
1062*2654012fSReza Sabdar 		(void) dbm_chunk_flush(bmp, cp);
1063*2654012fSReza Sabdar 
1064*2654012fSReza Sabdar 	TAILQ_REMOVE(&bmp->bm_lru, cp, c_lru);
1065*2654012fSReza Sabdar 	h = HASH(cp->c_off);
1066*2654012fSReza Sabdar 	hp = &bmp->bm_hash[h];
1067*2654012fSReza Sabdar 	TAILQ_REMOVE(hp, cp, c_hash);
1068*2654012fSReza Sabdar 	return (dbm_chunk_load(bmp, cp, bn, BMAP_OLD_CHUNK));
1069*2654012fSReza Sabdar }
1070*2654012fSReza Sabdar 
1071*2654012fSReza Sabdar 
1072*2654012fSReza Sabdar /*
1073*2654012fSReza Sabdar  * dbm_chunks_free
1074*2654012fSReza Sabdar  *
1075*2654012fSReza Sabdar  * Release the memory allocated for the chunks.
1076*2654012fSReza Sabdar  */
1077*2654012fSReza Sabdar static void
dbm_chunks_free(dbitmap_t * bmp)1078*2654012fSReza Sabdar dbm_chunks_free(dbitmap_t *bmp)
1079*2654012fSReza Sabdar {
1080*2654012fSReza Sabdar 	dbmap_list_t *headp;
1081*2654012fSReza Sabdar 	dbmap_chunk_t *cp;
1082*2654012fSReza Sabdar 
1083*2654012fSReza Sabdar 	if (!bmp)
1084*2654012fSReza Sabdar 		return;
1085*2654012fSReza Sabdar 
1086*2654012fSReza Sabdar 	headp = &bmp->bm_lru;
1087*2654012fSReza Sabdar 	if (!headp)
1088*2654012fSReza Sabdar 		return;
1089*2654012fSReza Sabdar 
1090*2654012fSReza Sabdar 	while (!TAILQ_EMPTY(headp)) {
1091*2654012fSReza Sabdar 		cp = TAILQ_FIRST(headp);
1092*2654012fSReza Sabdar 		TAILQ_REMOVE(headp, cp, c_lru);
1093*2654012fSReza Sabdar 		free(cp->c_bmp);
1094*2654012fSReza Sabdar 		free(cp);
1095*2654012fSReza Sabdar 	}
1096*2654012fSReza Sabdar }
1097*2654012fSReza Sabdar 
1098*2654012fSReza Sabdar 
1099*2654012fSReza Sabdar /*
1100*2654012fSReza Sabdar  * dbm_chunk_reposition
1101*2654012fSReza Sabdar  *
1102*2654012fSReza Sabdar  * Re-position the chunk in the LRU and the hash table.
1103*2654012fSReza Sabdar  */
1104*2654012fSReza Sabdar static void
dbm_chunk_reposition(dbitmap_t * bmp,dbmap_list_t * hp,dbmap_chunk_t * cp)1105*2654012fSReza Sabdar dbm_chunk_reposition(dbitmap_t *bmp, dbmap_list_t *hp, dbmap_chunk_t *cp)
1106*2654012fSReza Sabdar {
1107*2654012fSReza Sabdar 	if (bmp && hp && cp) {
1108*2654012fSReza Sabdar 		TAILQ_REMOVE(&bmp->bm_lru, cp, c_lru);
1109*2654012fSReza Sabdar 		TAILQ_INSERT_TAIL(&bmp->bm_lru, cp, c_lru);
1110*2654012fSReza Sabdar 		if (TAILQ_FIRST(hp) != cp) {
1111*2654012fSReza Sabdar 			TAILQ_REMOVE(hp, cp, c_hash);
1112*2654012fSReza Sabdar 			TAILQ_INSERT_HEAD(hp, cp, c_hash);
1113*2654012fSReza Sabdar 		}
1114*2654012fSReza Sabdar 	}
1115*2654012fSReza Sabdar }
1116*2654012fSReza Sabdar 
1117*2654012fSReza Sabdar 
1118*2654012fSReza Sabdar /*
1119*2654012fSReza Sabdar  * dbm_chunk_find
1120*2654012fSReza Sabdar  *
1121*2654012fSReza Sabdar  * Find and return the chunks which holds the specified bit.
1122*2654012fSReza Sabdar  * Allocate the chunk if necessary and re-position it in the
1123*2654012fSReza Sabdar  * LRU and hash table lists.
1124*2654012fSReza Sabdar  */
1125*2654012fSReza Sabdar static dbmap_chunk_t *
dbm_chunk_find(dbitmap_t * bmp,u_quad_t bn)1126*2654012fSReza Sabdar dbm_chunk_find(dbitmap_t *bmp, u_quad_t bn)
1127*2654012fSReza Sabdar {
1128*2654012fSReza Sabdar 	int h;
1129*2654012fSReza Sabdar 	dbmap_chunk_t *cp;
1130*2654012fSReza Sabdar 	dbmap_list_t *hp;
1131*2654012fSReza Sabdar 
1132*2654012fSReza Sabdar 	if (!bmp)
1133*2654012fSReza Sabdar 		return (NULL);
1134*2654012fSReza Sabdar 
1135*2654012fSReza Sabdar 	h = HASH(bn);
1136*2654012fSReza Sabdar 	hp = &bmp->bm_hash[h];
1137*2654012fSReza Sabdar 	TAILQ_FOREACH(cp, hp, c_hash) {
1138*2654012fSReza Sabdar 		if (bn >= cp->c_off && bn < (cp->c_off + cp->c_clen)) {
1139*2654012fSReza Sabdar 			bitmap_stats.bs_cache_hit++;
1140*2654012fSReza Sabdar 
1141*2654012fSReza Sabdar 			dbm_chunk_reposition(bmp, hp, cp);
1142*2654012fSReza Sabdar 			return (cp);
1143*2654012fSReza Sabdar 		}
1144*2654012fSReza Sabdar 	}
1145*2654012fSReza Sabdar 
1146*2654012fSReza Sabdar 	bitmap_stats.bs_cache_miss++;
1147*2654012fSReza Sabdar 
1148*2654012fSReza Sabdar 	return (dbm_chunk_alloc(bmp, bn));
1149*2654012fSReza Sabdar }
1150*2654012fSReza Sabdar 
1151*2654012fSReza Sabdar 
1152*2654012fSReza Sabdar /*
1153*2654012fSReza Sabdar  * dbmp_setval
1154*2654012fSReza Sabdar  *
1155*2654012fSReza Sabdar  * Set a range of bits in the bitmap specified by the
1156*2654012fSReza Sabdar  * vector.
1157*2654012fSReza Sabdar  */
1158*2654012fSReza Sabdar static int
dbmp_setval(dbitmap_t * bmp,bm_iovec_t * vp)1159*2654012fSReza Sabdar dbmp_setval(dbitmap_t *bmp, bm_iovec_t *vp)
1160*2654012fSReza Sabdar {
1161*2654012fSReza Sabdar 	int rv;
1162*2654012fSReza Sabdar 	u_quad_t cl;
1163*2654012fSReza Sabdar 	u_quad_t bn;
1164*2654012fSReza Sabdar 	u_quad_t max;
1165*2654012fSReza Sabdar 	dbmap_chunk_t *cp;
1166*2654012fSReza Sabdar 
1167*2654012fSReza Sabdar 	bn = vp->bmv_base;
1168*2654012fSReza Sabdar 	max = bn + vp->bmv_len;
1169*2654012fSReza Sabdar 	if (bn >= bmp->bm_len || max > bmp->bm_len)
1170*2654012fSReza Sabdar 		return (-EINVAL);
1171*2654012fSReza Sabdar 
1172*2654012fSReza Sabdar 	if (*vp->bmv_val) {
1173*2654012fSReza Sabdar 		bitmap_stats.bs_set++;
1174*2654012fSReza Sabdar 		bitmap_stats.bs_set_bits += vp->bmv_len;
1175*2654012fSReza Sabdar 	} else {
1176*2654012fSReza Sabdar 		bitmap_stats.bs_unset++;
1177*2654012fSReza Sabdar 		bitmap_stats.bs_unset_bits += vp->bmv_len;
1178*2654012fSReza Sabdar 	}
1179*2654012fSReza Sabdar 
1180*2654012fSReza Sabdar 	do {
1181*2654012fSReza Sabdar 		cp = dbm_chunk_find(bmp, bn);
1182*2654012fSReza Sabdar 		if (!cp)
1183*2654012fSReza Sabdar 			return (-ERANGE);
1184*2654012fSReza Sabdar 
1185*2654012fSReza Sabdar 		for (cl = cp->c_off + cp->c_clen; bn < cl && bn < max; bn++) {
1186*2654012fSReza Sabdar 			rv = dbmp_set(cp, bn, vp->bmv_val);
1187*2654012fSReza Sabdar 			if (rv != 0)
1188*2654012fSReza Sabdar 				return (rv);
1189*2654012fSReza Sabdar 		}
1190*2654012fSReza Sabdar 	} while (bn < max);
1191*2654012fSReza Sabdar 
1192*2654012fSReza Sabdar 	return (0);
1193*2654012fSReza Sabdar }
1194*2654012fSReza Sabdar 
1195*2654012fSReza Sabdar 
1196*2654012fSReza Sabdar /*
1197*2654012fSReza Sabdar  * dbmp_getval
1198*2654012fSReza Sabdar  *
1199*2654012fSReza Sabdar  * Get a range of bits in the bitmap specified by the
1200*2654012fSReza Sabdar  * vector.
1201*2654012fSReza Sabdar  */
1202*2654012fSReza Sabdar static int
dbmp_getval(dbitmap_t * bmp,bm_iovec_t * vp)1203*2654012fSReza Sabdar dbmp_getval(dbitmap_t *bmp, bm_iovec_t *vp)
1204*2654012fSReza Sabdar {
1205*2654012fSReza Sabdar 	uint_t cnt;
1206*2654012fSReza Sabdar 	uint_t *ip;
1207*2654012fSReza Sabdar 	int rv;
1208*2654012fSReza Sabdar 	u_quad_t cl;
1209*2654012fSReza Sabdar 	u_quad_t bn;
1210*2654012fSReza Sabdar 	u_quad_t max;
1211*2654012fSReza Sabdar 	dbmap_chunk_t *cp;
1212*2654012fSReza Sabdar 
1213*2654012fSReza Sabdar 	bn = vp->bmv_base;
1214*2654012fSReza Sabdar 	max = bn + vp->bmv_len;
1215*2654012fSReza Sabdar 	if (bn >= bmp->bm_len || max > bmp->bm_len)
1216*2654012fSReza Sabdar 		return (-EINVAL);
1217*2654012fSReza Sabdar 
1218*2654012fSReza Sabdar 	bitmap_stats.bs_get++;
1219*2654012fSReza Sabdar 	bitmap_stats.bs_get_bits += 1;
1220*2654012fSReza Sabdar 
1221*2654012fSReza Sabdar 	cnt = 0;
1222*2654012fSReza Sabdar 	ip = vp->bmv_val;
1223*2654012fSReza Sabdar 	*ip = 0;
1224*2654012fSReza Sabdar 	do {
1225*2654012fSReza Sabdar 		cp = dbm_chunk_find(bmp, bn);
1226*2654012fSReza Sabdar 		if (!cp)
1227*2654012fSReza Sabdar 			return (-ERANGE);
1228*2654012fSReza Sabdar 
1229*2654012fSReza Sabdar 		for (cl = cp->c_off + cp->c_clen; bn < cl && bn < max; bn++) {
1230*2654012fSReza Sabdar 			rv = dbmp_get(cp, bn);
1231*2654012fSReza Sabdar 			if (rv < 0)
1232*2654012fSReza Sabdar 				return (rv);
1233*2654012fSReza Sabdar 
1234*2654012fSReza Sabdar 			*ip |= rv << cnt;
1235*2654012fSReza Sabdar 			if (++cnt >= BMAP_BPW) {
1236*2654012fSReza Sabdar 				*++ip = 0;
1237*2654012fSReza Sabdar 				cnt = 0;
1238*2654012fSReza Sabdar 			}
1239*2654012fSReza Sabdar 		}
1240*2654012fSReza Sabdar 	} while (bn < max);
1241*2654012fSReza Sabdar 
1242*2654012fSReza Sabdar 	return (0);
1243*2654012fSReza Sabdar }
1244*2654012fSReza Sabdar 
1245*2654012fSReza Sabdar 
1246*2654012fSReza Sabdar /*
1247*2654012fSReza Sabdar  * dbyte_apply_ifset
1248*2654012fSReza Sabdar  *
1249*2654012fSReza Sabdar  * Apply the function on the set bits of the specified word.
1250*2654012fSReza Sabdar  */
1251*2654012fSReza Sabdar static int
dbyte_apply_ifset(dbitmap_t * bmp,u_quad_t off,uint_t b,int (* fp)(),void * arg)1252*2654012fSReza Sabdar dbyte_apply_ifset(dbitmap_t *bmp, u_quad_t off, uint_t b, int(*fp)(),
1253*2654012fSReza Sabdar     void *arg)
1254*2654012fSReza Sabdar {
1255*2654012fSReza Sabdar 	int bmd;
1256*2654012fSReza Sabdar 	int rv;
1257*2654012fSReza Sabdar 	u_quad_t l;
1258*2654012fSReza Sabdar 
1259*2654012fSReza Sabdar 	rv = 0;
1260*2654012fSReza Sabdar 	l = dbmp_getlen(bmp);
1261*2654012fSReza Sabdar 	bmd = dbmp2bmd(bmp);
1262*2654012fSReza Sabdar 	for (; b && off < l; off++) {
1263*2654012fSReza Sabdar 		if (b & 1) {
1264*2654012fSReza Sabdar 			bitmap_stats.bs_set_applied++;
1265*2654012fSReza Sabdar 
1266*2654012fSReza Sabdar 			if ((rv = (*fp)(bmd, off, arg)))
1267*2654012fSReza Sabdar 				break;
1268*2654012fSReza Sabdar 		}
1269*2654012fSReza Sabdar 		b >>= 1;
1270*2654012fSReza Sabdar 	}
1271*2654012fSReza Sabdar 
1272*2654012fSReza Sabdar 	return (rv);
1273*2654012fSReza Sabdar }
1274*2654012fSReza Sabdar 
1275*2654012fSReza Sabdar 
1276*2654012fSReza Sabdar /*
1277*2654012fSReza Sabdar  * dbm_chunk_apply_ifset
1278*2654012fSReza Sabdar  *
1279*2654012fSReza Sabdar  * Apply the function on the set bits of the specified chunk.
1280*2654012fSReza Sabdar  */
1281*2654012fSReza Sabdar static int
dbm_chunk_apply_ifset(dbitmap_t * bmp,dbmap_chunk_t * cp,int (* fp)(),void * arg)1282*2654012fSReza Sabdar dbm_chunk_apply_ifset(dbitmap_t *bmp, dbmap_chunk_t *cp, int(*fp)(),
1283*2654012fSReza Sabdar     void *arg)
1284*2654012fSReza Sabdar {
1285*2654012fSReza Sabdar 	int rv;
1286*2654012fSReza Sabdar 	uint_t *bp;
1287*2654012fSReza Sabdar 	uint_t i, m;
1288*2654012fSReza Sabdar 	u_quad_t q;
1289*2654012fSReza Sabdar 
1290*2654012fSReza Sabdar 	rv = 0;
1291*2654012fSReza Sabdar 	bp = cp->c_bmp;
1292*2654012fSReza Sabdar 	q = cp->c_off;
1293*2654012fSReza Sabdar 	m = cp->c_mlen / BMAP_WSIZE;
1294*2654012fSReza Sabdar 	for (i = 0; i < m; q += BMAP_BPW, bp++, i++)
1295*2654012fSReza Sabdar 		if (*bp) {
1296*2654012fSReza Sabdar 			rv = dbyte_apply_ifset(bmp, q, *bp, fp, arg);
1297*2654012fSReza Sabdar 			if (rv != 0)
1298*2654012fSReza Sabdar 				break;
1299*2654012fSReza Sabdar 		}
1300*2654012fSReza Sabdar 
1301*2654012fSReza Sabdar 	return (rv);
1302*2654012fSReza Sabdar }
1303*2654012fSReza Sabdar 
1304*2654012fSReza Sabdar 
1305*2654012fSReza Sabdar /*
1306*2654012fSReza Sabdar  * swfile_trunc
1307*2654012fSReza Sabdar  *
1308*2654012fSReza Sabdar  * Truncate the rest of the swap file.
1309*2654012fSReza Sabdar  */
1310*2654012fSReza Sabdar static int
swfile_trunc(int fd)1311*2654012fSReza Sabdar swfile_trunc(int fd)
1312*2654012fSReza Sabdar {
1313*2654012fSReza Sabdar 	int rv;
1314*2654012fSReza Sabdar 	off_t off;
1315*2654012fSReza Sabdar 
1316*2654012fSReza Sabdar 	/*
1317*2654012fSReza Sabdar 	 * Get the current offset and truncate whatever is
1318*2654012fSReza Sabdar 	 * after this point.
1319*2654012fSReza Sabdar 	 */
1320*2654012fSReza Sabdar 	rv = 0;
1321*2654012fSReza Sabdar 	if ((off = lseek(fd, 0, SEEK_CUR)) < 0)
1322*2654012fSReza Sabdar 		rv = -1;
1323*2654012fSReza Sabdar 	else if (ftruncate(fd, off) != 0)
1324*2654012fSReza Sabdar 		rv = -1;
1325*2654012fSReza Sabdar 
1326*2654012fSReza Sabdar 	return (rv);
1327*2654012fSReza Sabdar }
1328*2654012fSReza Sabdar 
1329*2654012fSReza Sabdar 
1330*2654012fSReza Sabdar /*
1331*2654012fSReza Sabdar  * swfile_init
1332*2654012fSReza Sabdar  *
1333*2654012fSReza Sabdar  * Initialize the swap file.  The necessary disk space is
1334*2654012fSReza Sabdar  * reserved by writing to the swap file for swapping the
1335*2654012fSReza Sabdar  * chunks in/out of the file.
1336*2654012fSReza Sabdar  */
1337*2654012fSReza Sabdar static int
swfile_init(int fd,u_quad_t len,int set)1338*2654012fSReza Sabdar swfile_init(int fd, u_quad_t len, int set)
1339*2654012fSReza Sabdar {
1340*2654012fSReza Sabdar 	u_quad_t i, n;
1341*2654012fSReza Sabdar 	uint_t cl, ml;
1342*2654012fSReza Sabdar 	uint_t buf[BMAP_CHUNK_WORDS];
1343*2654012fSReza Sabdar 
1344*2654012fSReza Sabdar 	(void) memset(buf, set ? 0xff : 0x00, BMAP_CHUNK_BYTES);
1345*2654012fSReza Sabdar 	n = len / BMAP_CHUNK_BITS;
1346*2654012fSReza Sabdar 	for (i = 0; i < n; i++)
1347*2654012fSReza Sabdar 		if (write(fd, buf, BMAP_CHUNK_BYTES) != BMAP_CHUNK_BYTES)
1348*2654012fSReza Sabdar 			return (-1);
1349*2654012fSReza Sabdar 
1350*2654012fSReza Sabdar 	cl = (uint_t)(len % BMAP_CHUNK_BITS);
1351*2654012fSReza Sabdar 	ml = MEM_LEN(cl);
1352*2654012fSReza Sabdar 	if (write(fd, buf, ml) != ml)
1353*2654012fSReza Sabdar 		return (-1);
1354*2654012fSReza Sabdar 
1355*2654012fSReza Sabdar 	return (swfile_trunc(fd));
1356*2654012fSReza Sabdar }
1357*2654012fSReza Sabdar 
1358*2654012fSReza Sabdar 
1359*2654012fSReza Sabdar /*
1360*2654012fSReza Sabdar  * dbm_alloc
1361*2654012fSReza Sabdar  *
1362*2654012fSReza Sabdar  * Allocate a bit map and return a handle to it.
1363*2654012fSReza Sabdar  *
1364*2654012fSReza Sabdar  * The swap file is created if it does not exist.
1365*2654012fSReza Sabdar  * The file is truncated if it exists and is larger
1366*2654012fSReza Sabdar  * than needed amount.
1367*2654012fSReza Sabdar  *
1368*2654012fSReza Sabdar  * The hash table and LRU list are empty at this point.
1369*2654012fSReza Sabdar  * They are allocated and/or loaded on-demand.
1370*2654012fSReza Sabdar  */
1371*2654012fSReza Sabdar int
dbm_alloc(char * fname,u_quad_t len,int set)1372*2654012fSReza Sabdar dbm_alloc(char *fname, u_quad_t len, int set)
1373*2654012fSReza Sabdar {
1374*2654012fSReza Sabdar 	int fd;
1375*2654012fSReza Sabdar 	int bmd;
1376*2654012fSReza Sabdar 	dbitmap_t *bmp;
1377*2654012fSReza Sabdar 
1378*2654012fSReza Sabdar 	if (!fname || !*fname || !len)
1379*2654012fSReza Sabdar 		return (-1);
1380*2654012fSReza Sabdar 
1381*2654012fSReza Sabdar 	/*
1382*2654012fSReza Sabdar 	 * When allocating bitmap, make sure there is enough
1383*2654012fSReza Sabdar 	 * disk space by allocating needed disk space, for
1384*2654012fSReza Sabdar 	 * writing back the dirty chunks when swaping them out.
1385*2654012fSReza Sabdar 	 */
1386*2654012fSReza Sabdar 	bmd = dbmd_alloc();
1387*2654012fSReza Sabdar 	if (bmd < 0)
1388*2654012fSReza Sabdar 		return (bmd);
1389*2654012fSReza Sabdar 
1390*2654012fSReza Sabdar 	bmp = bmd2dbmp(bmd);
1391*2654012fSReza Sabdar 	if ((fd = open(fname, O_RDWR|O_CREAT, 0600)) < 0)
1392*2654012fSReza Sabdar 		bmd = -1;
1393*2654012fSReza Sabdar 	else if (swfile_init(fd, len, set) < 0) {
1394*2654012fSReza Sabdar 		bmd = -1;
1395*2654012fSReza Sabdar 		(void) close(fd);
1396*2654012fSReza Sabdar 		(void) unlink(fname);
1397*2654012fSReza Sabdar 		dbmd_free(bmd);
1398*2654012fSReza Sabdar 		bmd = -1;
1399*2654012fSReza Sabdar 	} else if (!(bmp->bm_fname = strdup(fname))) {
1400*2654012fSReza Sabdar 		(void) close(fd);
1401*2654012fSReza Sabdar 		(void) unlink(fname);
1402*2654012fSReza Sabdar 		dbmd_free(bmd);
1403*2654012fSReza Sabdar 		bmd = -1;
1404*2654012fSReza Sabdar 	} else {
1405*2654012fSReza Sabdar 		bitmap_stats.bs_alloc_cnt++;
1406*2654012fSReza Sabdar 		bitmap_stats.bs_alloc_size += len;
1407*2654012fSReza Sabdar 
1408*2654012fSReza Sabdar 		bmp->bm_fd = fd;
1409*2654012fSReza Sabdar 		if (set)
1410*2654012fSReza Sabdar 			BMAP_SET_FLAGS(bmp, BMAP_BINIT_ONES);
1411*2654012fSReza Sabdar 		else
1412*2654012fSReza Sabdar 			BMAP_UNSET_FLAGS(bmp, BMAP_BINIT_ONES);
1413*2654012fSReza Sabdar 		bmp->bm_len = len;
1414*2654012fSReza Sabdar 		bmp->bm_ccur = 0;
1415*2654012fSReza Sabdar 		bmp->bm_cmax = BMAP_CHUNK_MAX;
1416*2654012fSReza Sabdar 		TAILQ_INIT(&bmp->bm_lru);
1417*2654012fSReza Sabdar 		hash_init((bmap_list_t *)bmp->bm_hash);
1418*2654012fSReza Sabdar 	}
1419*2654012fSReza Sabdar 
1420*2654012fSReza Sabdar 	return (bmd);
1421*2654012fSReza Sabdar }
1422*2654012fSReza Sabdar 
1423*2654012fSReza Sabdar 
1424*2654012fSReza Sabdar /*
1425*2654012fSReza Sabdar  * dbm_free
1426*2654012fSReza Sabdar  *
1427*2654012fSReza Sabdar  * Free memory allocated for the bitmap and remove its swap file.
1428*2654012fSReza Sabdar  */
1429*2654012fSReza Sabdar int
dbm_free(int bmd)1430*2654012fSReza Sabdar dbm_free(int bmd)
1431*2654012fSReza Sabdar {
1432*2654012fSReza Sabdar 	int rv;
1433*2654012fSReza Sabdar 	dbitmap_t *bmp;
1434*2654012fSReza Sabdar 
1435*2654012fSReza Sabdar 	bmp = bmd2dbmp(bmd);
1436*2654012fSReza Sabdar 	if (bmp && BMAP_IS_INUSE(bmp)) {
1437*2654012fSReza Sabdar 		bitmap_stats.bs_free_cnt++;
1438*2654012fSReza Sabdar 
1439*2654012fSReza Sabdar 		dbm_chunks_free(bmp);
1440*2654012fSReza Sabdar 		(void) close(bmp->bm_fd);
1441*2654012fSReza Sabdar 		(void) unlink(bmp->bm_fname);
1442*2654012fSReza Sabdar 		free(bmp->bm_fname);
1443*2654012fSReza Sabdar 		dbmd_free(bmd);
1444*2654012fSReza Sabdar 		rv = 0;
1445*2654012fSReza Sabdar 	} else
1446*2654012fSReza Sabdar 		rv = -1;
1447*2654012fSReza Sabdar 
1448*2654012fSReza Sabdar 	return (rv);
1449*2654012fSReza Sabdar }
1450*2654012fSReza Sabdar 
1451*2654012fSReza Sabdar 
1452*2654012fSReza Sabdar /*
1453*2654012fSReza Sabdar  * dbm_getlen
1454*2654012fSReza Sabdar  *
1455*2654012fSReza Sabdar  * Return length of the bitmap.
1456*2654012fSReza Sabdar  */
1457*2654012fSReza Sabdar u_quad_t
dbm_getlen(int bmd)1458*2654012fSReza Sabdar dbm_getlen(int bmd)
1459*2654012fSReza Sabdar {
1460*2654012fSReza Sabdar 	dbitmap_t *bmp;
1461*2654012fSReza Sabdar 
1462*2654012fSReza Sabdar 	bmp = bmd2dbmp(bmd);
1463*2654012fSReza Sabdar 	return (dbmp_getlen(bmp));
1464*2654012fSReza Sabdar }
1465*2654012fSReza Sabdar 
1466*2654012fSReza Sabdar 
1467*2654012fSReza Sabdar /*
1468*2654012fSReza Sabdar  * dbm_set
1469*2654012fSReza Sabdar  *
1470*2654012fSReza Sabdar  * Set a range of bits.
1471*2654012fSReza Sabdar  */
1472*2654012fSReza Sabdar int
dbm_set(int bmd,u_quad_t start,u_quad_t len,uint_t val)1473*2654012fSReza Sabdar dbm_set(int bmd, u_quad_t start, u_quad_t len, uint_t val)
1474*2654012fSReza Sabdar {
1475*2654012fSReza Sabdar 	bm_io_t io;
1476*2654012fSReza Sabdar 	bm_iovec_t iov;
1477*2654012fSReza Sabdar 
1478*2654012fSReza Sabdar 	iov.bmv_base = start;
1479*2654012fSReza Sabdar 	iov.bmv_len = len;
1480*2654012fSReza Sabdar 	iov.bmv_val = &val;
1481*2654012fSReza Sabdar 	io.bmio_iovcnt = 1;
1482*2654012fSReza Sabdar 	io.bmio_iov = &iov;
1483*2654012fSReza Sabdar 
1484*2654012fSReza Sabdar 	return (dbm_setiov(bmd, &io));
1485*2654012fSReza Sabdar }
1486*2654012fSReza Sabdar 
1487*2654012fSReza Sabdar 
1488*2654012fSReza Sabdar /*
1489*2654012fSReza Sabdar  * dbm_getiov
1490*2654012fSReza Sabdar  *
1491*2654012fSReza Sabdar  * Get bits specified by the array of vectors.
1492*2654012fSReza Sabdar  */
1493*2654012fSReza Sabdar int
dbm_getiov(int bmd,bm_io_t * iop)1494*2654012fSReza Sabdar dbm_getiov(int bmd, bm_io_t *iop)
1495*2654012fSReza Sabdar {
1496*2654012fSReza Sabdar 	int i;
1497*2654012fSReza Sabdar 	int rv;
1498*2654012fSReza Sabdar 	bm_iovec_t *vp;
1499*2654012fSReza Sabdar 	dbitmap_t *bmp;
1500*2654012fSReza Sabdar 
1501*2654012fSReza Sabdar 	if (!iop)
1502*2654012fSReza Sabdar 		rv = -EINVAL;
1503*2654012fSReza Sabdar 	else if (!(bmp = bmd2dbmp(bmd)))
1504*2654012fSReza Sabdar 		rv = -EINVAL;
1505*2654012fSReza Sabdar 	else if (iop->bmio_iovcnt <= 0)
1506*2654012fSReza Sabdar 		rv = -EINVAL;
1507*2654012fSReza Sabdar 	else {
1508*2654012fSReza Sabdar 		rv = 0;
1509*2654012fSReza Sabdar 		vp = iop->bmio_iov;
1510*2654012fSReza Sabdar 		for (i = 0; i < iop->bmio_iovcnt; vp++, i++) {
1511*2654012fSReza Sabdar 			if (!vp)
1512*2654012fSReza Sabdar 				return (-EINVAL);
1513*2654012fSReza Sabdar 			rv |= dbmp_getval(bmp, vp);
1514*2654012fSReza Sabdar 		}
1515*2654012fSReza Sabdar 	}
1516*2654012fSReza Sabdar 
1517*2654012fSReza Sabdar 	return (rv);
1518*2654012fSReza Sabdar }
1519*2654012fSReza Sabdar 
1520*2654012fSReza Sabdar 
1521*2654012fSReza Sabdar /*
1522*2654012fSReza Sabdar  * dbm_setiov
1523*2654012fSReza Sabdar  *
1524*2654012fSReza Sabdar  * Set bits specified by the array of vectors.
1525*2654012fSReza Sabdar  */
1526*2654012fSReza Sabdar int
dbm_setiov(int bmd,bm_io_t * iop)1527*2654012fSReza Sabdar dbm_setiov(int bmd, bm_io_t *iop)
1528*2654012fSReza Sabdar {
1529*2654012fSReza Sabdar 	int i;
1530*2654012fSReza Sabdar 	int rv;
1531*2654012fSReza Sabdar 	bm_iovec_t *vp;
1532*2654012fSReza Sabdar 	dbitmap_t *bmp;
1533*2654012fSReza Sabdar 
1534*2654012fSReza Sabdar 	if (!iop)
1535*2654012fSReza Sabdar 		rv = -EINVAL;
1536*2654012fSReza Sabdar 	else if (!(bmp = bmd2dbmp(bmd)))
1537*2654012fSReza Sabdar 		rv = -EINVAL;
1538*2654012fSReza Sabdar 	else if (iop->bmio_iovcnt <= 0)
1539*2654012fSReza Sabdar 		rv = -EINVAL;
1540*2654012fSReza Sabdar 	else if (!iop->bmio_iov)
1541*2654012fSReza Sabdar 		rv = -EINVAL;
1542*2654012fSReza Sabdar 	else {
1543*2654012fSReza Sabdar 		rv = 0;
1544*2654012fSReza Sabdar 		vp = iop->bmio_iov;
1545*2654012fSReza Sabdar 		for (i = 0; i < iop->bmio_iovcnt; vp++, i++)
1546*2654012fSReza Sabdar 			rv |= dbmp_setval(bmp, vp);
1547*2654012fSReza Sabdar 	}
1548*2654012fSReza Sabdar 
1549*2654012fSReza Sabdar 	return (rv);
1550*2654012fSReza Sabdar }
1551*2654012fSReza Sabdar 
1552*2654012fSReza Sabdar 
1553*2654012fSReza Sabdar /*
1554*2654012fSReza Sabdar  * dbm_apply_ifset
1555*2654012fSReza Sabdar  *
1556*2654012fSReza Sabdar  * Call the callback function for each set bit in the bitmap and
1557*2654012fSReza Sabdar  * pass the 'arg' and bit number as its argument.
1558*2654012fSReza Sabdar  */
1559*2654012fSReza Sabdar int
dbm_apply_ifset(int bmd,int (* fp)(),void * arg)1560*2654012fSReza Sabdar dbm_apply_ifset(int bmd, int(*fp)(), void *arg)
1561*2654012fSReza Sabdar {
1562*2654012fSReza Sabdar 	int rv;
1563*2654012fSReza Sabdar 	u_quad_t q;
1564*2654012fSReza Sabdar 	dbitmap_t *bmp;
1565*2654012fSReza Sabdar 	dbmap_chunk_t *cp;
1566*2654012fSReza Sabdar 
1567*2654012fSReza Sabdar 	bmp = bmd2dbmp(bmd);
1568*2654012fSReza Sabdar 	if (!bmp || !fp)
1569*2654012fSReza Sabdar 		return (-EINVAL);
1570*2654012fSReza Sabdar 
1571*2654012fSReza Sabdar 	rv = 0;
1572*2654012fSReza Sabdar 	for (q = 0; q < bmp->bm_len; q += BMAP_CHUNK_BITS) {
1573*2654012fSReza Sabdar 		cp = dbm_chunk_find(bmp, q);
1574*2654012fSReza Sabdar 		if (!cp) {
1575*2654012fSReza Sabdar 			rv = -ERANGE;
1576*2654012fSReza Sabdar 			break;
1577*2654012fSReza Sabdar 		}
1578*2654012fSReza Sabdar 
1579*2654012fSReza Sabdar 		rv = dbm_chunk_apply_ifset(bmp, cp, fp, arg);
1580*2654012fSReza Sabdar 		if (rv != 0)
1581*2654012fSReza Sabdar 			break;
1582*2654012fSReza Sabdar 	}
1583*2654012fSReza Sabdar 
1584*2654012fSReza Sabdar 	return (rv);
1585*2654012fSReza Sabdar }
1586*2654012fSReza Sabdar 
1587*2654012fSReza Sabdar 
1588*2654012fSReza Sabdar /*
1589*2654012fSReza Sabdar  * bm_set
1590*2654012fSReza Sabdar  *
1591*2654012fSReza Sabdar  * Set a range of bits.
1592*2654012fSReza Sabdar  */
1593*2654012fSReza Sabdar int
bm_set(int bmd,u_quad_t start,u_quad_t len,uint_t val)1594*2654012fSReza Sabdar bm_set(int bmd, u_quad_t start, u_quad_t len, uint_t val)
1595*2654012fSReza Sabdar {
1596*2654012fSReza Sabdar 	bm_io_t io;
1597*2654012fSReza Sabdar 	bm_iovec_t iov;
1598*2654012fSReza Sabdar 
1599*2654012fSReza Sabdar 	iov.bmv_base = start;
1600*2654012fSReza Sabdar 	iov.bmv_len = len;
1601*2654012fSReza Sabdar 	iov.bmv_val = &val;
1602*2654012fSReza Sabdar 	io.bmio_iovcnt = 1;
1603*2654012fSReza Sabdar 	io.bmio_iov = &iov;
1604*2654012fSReza Sabdar 
1605*2654012fSReza Sabdar 	return (bm_setiov(bmd, &io));
1606*2654012fSReza Sabdar }
1607*2654012fSReza Sabdar 
1608*2654012fSReza Sabdar 
1609*2654012fSReza Sabdar /*
1610*2654012fSReza Sabdar  * bm_get
1611*2654012fSReza Sabdar  *
1612*2654012fSReza Sabdar  * Get a range of bits.
1613*2654012fSReza Sabdar  */
1614*2654012fSReza Sabdar int
bm_get(int bmd,u_quad_t start,u_quad_t len,uint_t * buf)1615*2654012fSReza Sabdar bm_get(int bmd, u_quad_t start, u_quad_t len, uint_t *buf)
1616*2654012fSReza Sabdar {
1617*2654012fSReza Sabdar 	bm_io_t io;
1618*2654012fSReza Sabdar 	bm_iovec_t iov;
1619*2654012fSReza Sabdar 
1620*2654012fSReza Sabdar 	iov.bmv_base = start;
1621*2654012fSReza Sabdar 	iov.bmv_len = len;
1622*2654012fSReza Sabdar 	iov.bmv_val = buf;
1623*2654012fSReza Sabdar 	io.bmio_iovcnt = 1;
1624*2654012fSReza Sabdar 	io.bmio_iov = &iov;
1625*2654012fSReza Sabdar 
1626*2654012fSReza Sabdar 	return (bm_getiov(bmd, &io));
1627*2654012fSReza Sabdar }
1628*2654012fSReza Sabdar 
1629*2654012fSReza Sabdar 
1630*2654012fSReza Sabdar /*
1631*2654012fSReza Sabdar  * bm_getone
1632*2654012fSReza Sabdar  *
1633*2654012fSReza Sabdar  * Get only one bit.
1634*2654012fSReza Sabdar  */
1635*2654012fSReza Sabdar int
bm_getone(int bmd,u_quad_t bitnum)1636*2654012fSReza Sabdar bm_getone(int bmd, u_quad_t bitnum)
1637*2654012fSReza Sabdar {
1638*2654012fSReza Sabdar 	uint_t i;
1639*2654012fSReza Sabdar 
1640*2654012fSReza Sabdar 	if (bm_get(bmd, bitnum, 1, &i) == 0)
1641*2654012fSReza Sabdar 		return (i ? 1 : 0);
1642*2654012fSReza Sabdar 
1643*2654012fSReza Sabdar 	return (0);
1644*2654012fSReza Sabdar }
1645*2654012fSReza Sabdar 
1646*2654012fSReza Sabdar 
1647*2654012fSReza Sabdar /*
1648*2654012fSReza Sabdar  * dbm_get
1649*2654012fSReza Sabdar  *
1650*2654012fSReza Sabdar  * Get a range of bits.
1651*2654012fSReza Sabdar  */
1652*2654012fSReza Sabdar int
dbm_get(int bmd,u_quad_t start,u_quad_t len,uint_t * buf)1653*2654012fSReza Sabdar dbm_get(int bmd, u_quad_t start, u_quad_t len, uint_t *buf)
1654*2654012fSReza Sabdar {
1655*2654012fSReza Sabdar 	bm_io_t io;
1656*2654012fSReza Sabdar 	bm_iovec_t iov;
1657*2654012fSReza Sabdar 
1658*2654012fSReza Sabdar 	iov.bmv_base = start;
1659*2654012fSReza Sabdar 	iov.bmv_len = len;
1660*2654012fSReza Sabdar 	iov.bmv_val = buf;
1661*2654012fSReza Sabdar 	io.bmio_iovcnt = 1;
1662*2654012fSReza Sabdar 	io.bmio_iov = &iov;
1663*2654012fSReza Sabdar 
1664*2654012fSReza Sabdar 	return (dbm_getiov(bmd, &io));
1665*2654012fSReza Sabdar }
1666*2654012fSReza Sabdar 
1667*2654012fSReza Sabdar 
1668*2654012fSReza Sabdar /*
1669*2654012fSReza Sabdar  * dbm_getone
1670*2654012fSReza Sabdar  *
1671*2654012fSReza Sabdar  * Get only one bit.
1672*2654012fSReza Sabdar  */
1673*2654012fSReza Sabdar int
dbm_getone(int bmd,u_quad_t bitnum)1674*2654012fSReza Sabdar dbm_getone(int bmd, u_quad_t bitnum)
1675*2654012fSReza Sabdar {
1676*2654012fSReza Sabdar 	uint_t i;
1677*2654012fSReza Sabdar 
1678*2654012fSReza Sabdar 	if (dbm_get(bmd, bitnum, 1, &i) == 0)
1679*2654012fSReza Sabdar 		return (i ? 1 : 0);
1680*2654012fSReza Sabdar 
1681*2654012fSReza Sabdar 	return (0);
1682*2654012fSReza Sabdar }
1683