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