8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / ndmpd / tlm / tlm_bitmap.c
blob03711cb718b3de2388ec5f26e43bab14d9b4ffdf
1 /*
2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 /*
7 * BSD 3 Clause License
9 * Copyright (c) 2007, The Storage Networking Industry Association.
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.
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.
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.
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.
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>
52 * Hash table size.
54 #define BMAP_HASH_SIZE 64
58 * Maximum number of chunk that can be cached.
60 #define BMAP_CHUNK_MAX 128
64 * Size of bitmap table.
66 #define BMAP_MAX 256
70 * Bit_MAP Word SIZE. This should be equal to 'sizeof (int)'.
72 #define BMAP_WSIZE (sizeof (int))
76 * Bit_MAP Bit Per Word.
78 #define BMAP_BPW (BMAP_WSIZE * 8)
79 #define BMAP_BPW_SHIFT 5
80 #define BMAP_BPW_MASK (~(~0 << BMAP_BPW_SHIFT))
84 * Chunk of bit map in each node.
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)
94 * Bitmap flags.
96 #define BMAP_BINIT_ONES 0x00000001 /* initial value of bits is 1 */
97 #define BMAP_INUSE 0x00000002 /* slot is in use */
101 * Macros of bitmap flags.
103 #define BMAP_SET_FLAGS(b, f) ((b)->bm_flags |= (f))
104 #define BMAP_UNSET_FLAGS(b, f) ((b)->bm_flags &= ~(f))
106 #define BMAP_IS_INIT_ONES(b) ((b)->bm_flags & BMAP_BINIT_ONES)
107 #define BMAP_IS_INUSE(b) ((b)->bm_flags & BMAP_INUSE)
110 #define HASH(p) (((p) / BMAP_CHUNK_BITS) % BMAP_HASH_SIZE)
113 * Calculate the memory size in bytes needed for the specified length
114 * of bitmap.
116 #define ROUNDUP(n, d) (((n) + (d) - 1) / (d))
117 #define MEM_LEN(l) (ROUNDUP((l), BMAP_BPW) * BMAP_WSIZE)
121 * Chunk flags.
123 #define BMAP_CSET_DIRTY(cp) (cp)->c_flags |= BMAP_CDIRTY
124 #define BMAP_CDIRTY 0x00000001 /* the chunk is dirty */
128 * Macros on chunk flags.
130 #define BMAP_CIS_DIRTY(cp) ((cp)->c_flags & BMAP_CDIRTY)
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.
138 #define BMAP_NEW_CHUNK 1
139 #define BMAP_OLD_CHUNK 0
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.
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.
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.
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;
168 TAILQ_HEAD(dbmap_list, dbmap_chunk);
169 typedef struct dbmap_list dbmap_list_t;
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;
184 * Disk bitmap table. Upon allocating a dbitmap, one slot
185 * of this table will be used.
187 static dbitmap_t dbitmap[BMAP_MAX];
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.
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.
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;
210 TAILQ_HEAD(bmap_list, bmap_chunk);
211 typedef struct bmap_list bmap_list_t;
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;
224 * Statistics gathering structure.
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;
247 * Disk bitmap table. Upon allocating a bitmap, one slot
248 * of this table will be used.
250 static bitmap_t bitmap[BMAP_MAX];
254 * Global instance of statistics variable.
256 bitmap_stats_t bitmap_stats;
260 * bmd2bmp
262 * Convert bitmap descriptor to bitmap pointer.
264 static bitmap_t *
265 bmd2bmp(int bmd)
267 if (bmd < 0 || bmd >= BMAP_MAX)
268 return (NULL);
270 return (&bitmap[bmd]);
275 * bmd_alloc
277 * Allocate a bitmap descriptor. Sets the INUSE flag of the slot.
279 static int
280 bmd_alloc(void)
282 int i;
283 bitmap_t *bmp;
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);
292 return (-1);
297 * bmd_free
299 * Free a bitmap descriptor. Clears the INUSE flag of the slot.
301 static void
302 bmd_free(int bmd)
304 bitmap_t *bmp;
306 bmp = bmd2bmp(bmd);
307 if (bmp)
308 BMAP_UNSET_FLAGS(bmp, BMAP_INUSE);
313 * bmp_set
315 * Generic function to set bit in a chunk. This can set or unset the
316 * specified bit.
318 static inline int
319 bmp_set(bmap_chunk_t *cp, u_quad_t bn, uint_t *vp)
321 int rv;
322 uint_t mask;
323 uint_t *ip;
324 uint_t v;
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;
336 return (rv);
341 * bmp_get
343 * Generic function to get bit in a chunk.
345 static inline int
346 bmp_get(bmap_chunk_t *cp, u_quad_t bn)
348 int rv;
349 uint_t bit;
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;
358 return (rv);
363 * bm_chuck_setup
365 * Set up the properties of the new chunk and position it in the hash list.
367 static bmap_chunk_t *
368 bm_chunk_setup(bitmap_t *bmp, bmap_chunk_t *cp, u_quad_t bn)
370 int h;
371 u_quad_t off, l;
372 uint_t cl, ml;
373 bmap_list_t *hp;
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);
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);
390 h = HASH(bn);
391 hp = &bmp->bm_hash[h];
393 TAILQ_INSERT_HEAD(hp, cp, c_hash);
394 cp->c_off = off;
395 cp->c_clen = cl;
396 cp->c_mlen = ml;
397 return (cp);
402 * bm_chunk_new
404 * Create a new chunk and keep track of memory used.
406 static bmap_chunk_t *
407 bm_chunk_new(bitmap_t *bmp, u_quad_t bn)
409 bmap_chunk_t *cp;
411 bitmap_stats.bs_chunk_new++;
413 cp = ndmp_malloc(sizeof (bmap_chunk_t));
414 if (cp) {
415 cp->c_bmp = ndmp_malloc(sizeof (uint_t) * BMAP_CHUNK_WORDS);
416 if (!cp->c_bmp) {
417 free(cp);
418 cp = NULL;
419 } else {
420 (void) bm_chunk_setup(bmp, cp, bn);
421 bmp->bm_ccur++;
425 return (cp);
430 * bm_chunk_alloc
432 * Allocate a chunk and return it. If the cache for the chunks is not
433 * fully used, a new chunk is created.
435 static bmap_chunk_t *
436 bm_chunk_alloc(bitmap_t *bmp, u_quad_t bn)
438 bmap_chunk_t *cp;
440 if (bmp->bm_ccur < bmp->bm_cmax)
441 cp = bm_chunk_new(bmp, bn);
442 else
443 cp = NULL;
445 return (cp);
450 * hash_free
452 * Free all chunks on the hash list.
454 void
455 hash_free(bmap_list_t *hp)
457 bmap_chunk_t *cp;
459 if (!hp)
460 return;
462 while (!TAILQ_EMPTY(hp)) {
463 cp = TAILQ_FIRST(hp);
464 TAILQ_REMOVE(hp, cp, c_hash);
465 free(cp->c_bmp);
466 free(cp);
472 * bm_chunks_free
474 * Release the memory allocated for the chunks.
476 static void
477 bm_chunks_free(bmap_list_t *hp)
479 int i;
481 for (i = 0; i < BMAP_HASH_SIZE; hp++, i++)
482 hash_free(hp);
487 * bm_chunk_repositions
489 * Re-position the chunk in the MRU hash table.
491 static void
492 bm_chunk_reposition(bitmap_t *bmp, bmap_list_t *hp, bmap_chunk_t *cp)
494 if (!bmp || !hp || !cp)
495 return;
497 if (TAILQ_FIRST(hp) != cp) {
498 TAILQ_REMOVE(hp, cp, c_hash);
499 TAILQ_INSERT_HEAD(hp, cp, c_hash);
505 * bm_chunk_find
507 * Find and return the chunks which holds the specified bit. Allocate
508 * the chunk if necessary and re-position it in the hash table lists.
510 static bmap_chunk_t *
511 bm_chunk_find(bitmap_t *bmp, u_quad_t bn)
513 int h;
514 bmap_chunk_t *cp;
515 bmap_list_t *hp;
517 if (!bmp)
518 return (NULL);
520 h = HASH(bn);
521 hp = &bmp->bm_hash[h];
522 TAILQ_FOREACH(cp, hp, c_hash) {
523 if (bn >= cp->c_off && bn < (cp->c_off + cp->c_clen)) {
524 bitmap_stats.bs_cache_hit++;
526 bm_chunk_reposition(bmp, hp, cp);
527 return (cp);
531 bitmap_stats.bs_cache_miss++;
533 return (bm_chunk_alloc(bmp, bn));
538 * bmp_setval
540 * Set a range of bits in the bitmap specified by the vector.
542 static int
543 bmp_setval(bitmap_t *bmp, bm_iovec_t *vp)
545 int rv;
546 u_quad_t cl;
547 u_quad_t bn;
548 u_quad_t max;
549 bmap_chunk_t *cp;
551 bn = vp->bmv_base;
552 max = bn + vp->bmv_len;
553 if (bn >= bmp->bm_len || max > bmp->bm_len)
554 return (-EINVAL);
556 if (*vp->bmv_val) {
557 bitmap_stats.bs_set++;
558 bitmap_stats.bs_set_bits += vp->bmv_len;
559 } else {
560 bitmap_stats.bs_unset++;
561 bitmap_stats.bs_unset_bits += vp->bmv_len;
564 do {
565 cp = bm_chunk_find(bmp, bn);
566 if (!cp)
567 return (-ERANGE);
569 for (cl = cp->c_off + cp->c_clen; bn < cl && bn < max; bn++) {
570 rv = bmp_set(cp, bn, vp->bmv_val);
571 if (rv != 0)
572 return (rv);
574 } while (bn < max);
576 return (0);
581 * bmp_getval
583 * Get a range of bits in the bitmap specified by the vector.
585 static int
586 bmp_getval(bitmap_t *bmp, bm_iovec_t *vp)
588 uint_t cnt;
589 uint_t *ip;
590 int rv;
591 u_quad_t cl;
592 u_quad_t bn;
593 u_quad_t max;
594 bmap_chunk_t *cp;
596 bn = vp->bmv_base;
597 max = bn + vp->bmv_len;
598 if (bn >= bmp->bm_len || max > bmp->bm_len)
599 return (-EINVAL);
601 bitmap_stats.bs_get++;
602 bitmap_stats.bs_get_bits += 1;
604 cnt = 0;
605 ip = vp->bmv_val;
606 *ip = 0;
607 do {
608 cp = bm_chunk_find(bmp, bn);
609 if (!cp)
610 return (-ERANGE);
612 for (cl = cp->c_off + cp->c_clen; bn < cl && bn < max; bn++) {
613 rv = bmp_get(cp, bn);
614 if (rv < 0)
615 return (rv);
617 *ip |= rv << cnt;
618 if (++cnt >= BMAP_BPW) {
619 *++ip = 0;
620 cnt = 0;
623 } while (bn < max);
625 return (0);
630 * hash_init
632 * Initialize the hash table lists head.
634 static void
635 hash_init(bmap_list_t *hp)
637 int i;
639 for (i = 0; i < BMAP_HASH_SIZE; hp++, i++) {
640 TAILQ_INIT(hp);
646 * bm_alloc
648 * Allocate a bit map and return a handle to it.
650 * The hash table list are empty at this point. They are allocated
651 * on demand.
654 bm_alloc(u_quad_t len, int set)
656 int bmd;
657 bitmap_t *bmp;
659 if (len == 0)
660 return (-1);
662 bmd = bmd_alloc();
663 if (bmd < 0)
664 return (bmd);
666 bmp = bmd2bmp(bmd);
667 bitmap_stats.bs_alloc_cnt++;
668 bitmap_stats.bs_alloc_size += len;
670 if (set)
671 BMAP_SET_FLAGS(bmp, BMAP_BINIT_ONES);
672 else
673 BMAP_UNSET_FLAGS(bmp, BMAP_BINIT_ONES);
674 bmp->bm_len = len;
675 bmp->bm_ccur = 0;
676 bmp->bm_cmax = BMAP_CHUNK_MAX;
677 hash_init(bmp->bm_hash);
679 return (bmd);
684 * bm_free
686 * Free memory allocated for the bitmap.
689 bm_free(int bmd)
691 int rv;
692 bitmap_t *bmp;
694 bmp = bmd2bmp(bmd);
695 if (bmp && BMAP_IS_INUSE(bmp)) {
696 bitmap_stats.bs_free_cnt++;
698 bm_chunks_free(bmp->bm_hash);
699 bmd_free(bmd);
700 rv = 0;
701 } else
702 rv = -1;
704 return (rv);
709 * bm_getiov
711 * Get bits specified by the array of vectors.
714 bm_getiov(int bmd, bm_io_t *iop)
716 int i;
717 int rv;
718 bm_iovec_t *vp;
719 bitmap_t *bmp;
721 if (!iop)
722 rv = -EINVAL;
723 else if (!(bmp = bmd2bmp(bmd)))
724 rv = -EINVAL;
725 else if (iop->bmio_iovcnt <= 0)
726 rv = -EINVAL;
727 else {
728 rv = 0;
729 vp = iop->bmio_iov;
730 for (i = 0; i < iop->bmio_iovcnt; vp++, i++) {
731 if (!vp)
732 return (-EINVAL);
733 rv |= bmp_getval(bmp, vp);
737 return (rv);
742 * bm_setiov
744 * Set bits specified by the array of vectors.
747 bm_setiov(int bmd, bm_io_t *iop)
749 int i;
750 int rv;
751 bm_iovec_t *vp;
752 bitmap_t *bmp;
754 if (!iop)
755 rv = -EINVAL;
756 else if (!(bmp = bmd2bmp(bmd)))
757 rv = -EINVAL;
758 else if (iop->bmio_iovcnt <= 0)
759 rv = -EINVAL;
760 else if (!iop->bmio_iov)
761 rv = -EINVAL;
762 else {
763 rv = 0;
764 vp = iop->bmio_iov;
765 for (i = 0; i < iop->bmio_iovcnt; vp++, i++)
766 rv |= bmp_setval(bmp, vp);
769 return (rv);
774 * bmd2dbmp
776 * Convert bitmap descriptor to bitmap pointer.
778 static dbitmap_t *
779 bmd2dbmp(int bmd)
781 if (bmd < 0 || bmd >= BMAP_MAX)
782 return (NULL);
784 return (&dbitmap[bmd]);
789 * dbmp2bmd
791 * Convert bitmap pointer to bitmap descriptor.
793 static int
794 dbmp2bmd(dbitmap_t *bmp)
796 int bmd;
798 bmd = bmp - dbitmap;
799 if (bmd < 0 || bmd >= BMAP_MAX)
800 bmd = -1;
802 return (bmd);
806 * dbmd_alloc
808 * Allocate a bitmap descriptor.
809 * Sets the INUSE flag of the slot.
811 static int
812 dbmd_alloc(void)
814 int i;
815 dbitmap_t *bmp;
817 bmp = dbitmap;
818 for (i = 0; i < BMAP_MAX; bmp++, i++)
819 if (!BMAP_IS_INUSE(bmp)) {
820 BMAP_SET_FLAGS(bmp, BMAP_INUSE);
821 return (i);
824 return (-1);
829 * dbmd_free
831 * Free a bitmap descriptor.
832 * Clears the INUSE flag of the slot.
834 static void
835 dbmd_free(int bmd)
837 dbitmap_t *bmp;
839 bmp = bmd2dbmp(bmd);
840 if (bmp)
841 BMAP_UNSET_FLAGS(bmp, BMAP_INUSE);
846 * dbmp_set
848 * Generic function to set bit in a chunk. This can
849 * set or unset the specified bit.
851 static inline int
852 dbmp_set(dbmap_chunk_t *cp, u_quad_t bn, uint_t *vp)
854 int rv;
855 uint_t mask;
856 uint_t *ip;
857 uint_t v;
859 bn -= cp->c_off;
860 if (bn < cp->c_clen) {
861 mask = 1 <<(bn & BMAP_BPW_MASK);
862 ip = &cp->c_bmp[bn >> BMAP_BPW_SHIFT];
863 v = (*vp <<(bn & BMAP_BPW_MASK)) & mask;
864 *ip = (*ip & ~mask) | v;
865 BMAP_CSET_DIRTY(cp);
866 rv = 0;
867 } else
868 rv = -ERANGE;
870 return (rv);
875 * dbmp_getlen
877 * Get length of the bitmap.
879 static u_quad_t
880 dbmp_getlen(dbitmap_t *bmp)
882 return (bmp ? bmp->bm_len : 0LL);
887 * dbmp_get
889 * Generic function to get bit in a chunk.
891 static inline int
892 dbmp_get(dbmap_chunk_t *cp, u_quad_t bn)
894 int rv;
895 uint_t bit;
897 bn -= cp->c_off;
898 if (bn < cp->c_clen) {
899 bit = 1 <<(bn & BMAP_BPW_MASK);
900 rv = (cp->c_bmp[bn >> BMAP_BPW_SHIFT] & bit) != 0;
901 } else
902 rv = -ERANGE;
904 return (rv);
909 * dbm_chunk_seek
911 * Seek in the file where the chunk is saved or should be saved.
913 static int
914 dbm_chunk_seek(dbitmap_t *bmp, u_quad_t bn)
916 int rv;
917 off_t off;
919 if (!bmp)
920 rv = -1;
921 else {
922 off = BMAP_CHUNK_NO(bn) * BMAP_CHUNK_BYTES;
923 rv = (lseek(bmp->bm_fd, off, SEEK_SET) != off) ? -1 : 0;
926 return (rv);
931 * dbm_chunk_flush
933 * Save a chunk to file.
935 static int
936 dbm_chunk_flush(dbitmap_t *bmp, dbmap_chunk_t *cp)
938 int rv;
940 bitmap_stats.bs_chunk_flush++;
941 if (!bmp || !cp)
942 rv = -1;
943 else if (dbm_chunk_seek(bmp, cp->c_off) != 0)
944 rv = -1;
945 else if (write(bmp->bm_fd, cp->c_bmp, cp->c_mlen) != cp->c_mlen)
946 rv = -1;
947 else
948 rv = 0;
950 return (rv);
955 * dbm_chunk_load
957 * Load a chunk from a file. If the chunk is a new one,
958 * instead of reading from the disk, the memory for the
959 * chunk is set to either all zeros or to all ones.
960 * Otherwise, if the chunk is not a new one, it's read
961 * from the disk.
963 * The new chunk is positioned in the LRU and hash table
964 * after its data is ready.
966 static dbmap_chunk_t *
967 dbm_chunk_load(dbitmap_t *bmp, dbmap_chunk_t *cp, u_quad_t bn, int new)
969 int h;
970 u_quad_t off, l;
971 uint_t cl, ml;
972 dbmap_list_t *hp;
974 off = BMAP_CHUNK_OFF(bn);
975 l = bmp->bm_len - off;
976 if (l >= BMAP_CHUNK_BITS) {
977 cl = BMAP_CHUNK_BITS;
978 ml = BMAP_CHUNK_BYTES;
979 } else {
980 cl = l;
981 ml = MEM_LEN(l);
984 if (new == BMAP_NEW_CHUNK) {
985 if (BMAP_IS_INIT_ONES(bmp))
986 (void) memset(cp->c_bmp, 0xff, ml);
987 else
988 (void) memset(cp->c_bmp, 0x00, ml);
989 } else { /* BMAP_OLD_CHUNK */
990 if (dbm_chunk_seek(bmp, bn) != 0)
991 cp = NULL;
992 else if (read(bmp->bm_fd, cp->c_bmp, ml) != ml)
993 cp = NULL;
996 if (cp) {
997 TAILQ_INSERT_TAIL(&bmp->bm_lru, cp, c_lru);
998 h = HASH(bn);
999 hp = &bmp->bm_hash[h];
1000 TAILQ_INSERT_HEAD(hp, cp, c_hash);
1001 cp->c_flags = 0;
1002 cp->c_off = off;
1003 cp->c_clen = cl;
1004 cp->c_mlen = ml;
1007 return (cp);
1012 * dbm_chunk_new
1014 * Create a new chunk and keep track of memory used.
1016 static dbmap_chunk_t *
1017 dbm_chunk_new(dbitmap_t *bmp, u_quad_t bn)
1019 dbmap_chunk_t *cp;
1021 bitmap_stats.bs_chunk_new++;
1022 cp = ndmp_malloc(sizeof (dbmap_chunk_t));
1023 if (cp) {
1024 cp->c_bmp = ndmp_malloc(sizeof (uint_t) * BMAP_CHUNK_WORDS);
1025 if (!cp->c_bmp) {
1026 free(cp);
1027 cp = NULL;
1028 } else if (!dbm_chunk_load(bmp, cp, bn, BMAP_NEW_CHUNK)) {
1029 free(cp->c_bmp);
1030 free(cp);
1031 cp = NULL;
1032 } else
1033 bmp->bm_ccur++;
1036 return (cp);
1041 * dbm_chunk_alloc
1043 * Allocate a chunk and return it. If the cache for the
1044 * chunks is not fully used, a new chunk is created.
1045 * Otherwise, the first chunk from the LRU list is reclaimed,
1046 * loaded and returned.
1048 static dbmap_chunk_t *
1049 dbm_chunk_alloc(dbitmap_t *bmp, u_quad_t bn)
1051 int h;
1052 dbmap_list_t *hp;
1053 dbmap_chunk_t *cp;
1055 if (bmp->bm_ccur < bmp->bm_cmax)
1056 return (dbm_chunk_new(bmp, bn));
1058 bitmap_stats.bs_chunk_reclaim++;
1060 cp = TAILQ_FIRST(&bmp->bm_lru);
1061 if (BMAP_CIS_DIRTY(cp))
1062 (void) dbm_chunk_flush(bmp, cp);
1064 TAILQ_REMOVE(&bmp->bm_lru, cp, c_lru);
1065 h = HASH(cp->c_off);
1066 hp = &bmp->bm_hash[h];
1067 TAILQ_REMOVE(hp, cp, c_hash);
1068 return (dbm_chunk_load(bmp, cp, bn, BMAP_OLD_CHUNK));
1073 * dbm_chunks_free
1075 * Release the memory allocated for the chunks.
1077 static void
1078 dbm_chunks_free(dbitmap_t *bmp)
1080 dbmap_list_t *headp;
1081 dbmap_chunk_t *cp;
1083 if (!bmp)
1084 return;
1086 headp = &bmp->bm_lru;
1087 if (!headp)
1088 return;
1090 while (!TAILQ_EMPTY(headp)) {
1091 cp = TAILQ_FIRST(headp);
1092 TAILQ_REMOVE(headp, cp, c_lru);
1093 free(cp->c_bmp);
1094 free(cp);
1100 * dbm_chunk_reposition
1102 * Re-position the chunk in the LRU and the hash table.
1104 static void
1105 dbm_chunk_reposition(dbitmap_t *bmp, dbmap_list_t *hp, dbmap_chunk_t *cp)
1107 if (bmp && hp && cp) {
1108 TAILQ_REMOVE(&bmp->bm_lru, cp, c_lru);
1109 TAILQ_INSERT_TAIL(&bmp->bm_lru, cp, c_lru);
1110 if (TAILQ_FIRST(hp) != cp) {
1111 TAILQ_REMOVE(hp, cp, c_hash);
1112 TAILQ_INSERT_HEAD(hp, cp, c_hash);
1119 * dbm_chunk_find
1121 * Find and return the chunks which holds the specified bit.
1122 * Allocate the chunk if necessary and re-position it in the
1123 * LRU and hash table lists.
1125 static dbmap_chunk_t *
1126 dbm_chunk_find(dbitmap_t *bmp, u_quad_t bn)
1128 int h;
1129 dbmap_chunk_t *cp;
1130 dbmap_list_t *hp;
1132 if (!bmp)
1133 return (NULL);
1135 h = HASH(bn);
1136 hp = &bmp->bm_hash[h];
1137 TAILQ_FOREACH(cp, hp, c_hash) {
1138 if (bn >= cp->c_off && bn < (cp->c_off + cp->c_clen)) {
1139 bitmap_stats.bs_cache_hit++;
1141 dbm_chunk_reposition(bmp, hp, cp);
1142 return (cp);
1146 bitmap_stats.bs_cache_miss++;
1148 return (dbm_chunk_alloc(bmp, bn));
1153 * dbmp_setval
1155 * Set a range of bits in the bitmap specified by the
1156 * vector.
1158 static int
1159 dbmp_setval(dbitmap_t *bmp, bm_iovec_t *vp)
1161 int rv;
1162 u_quad_t cl;
1163 u_quad_t bn;
1164 u_quad_t max;
1165 dbmap_chunk_t *cp;
1167 bn = vp->bmv_base;
1168 max = bn + vp->bmv_len;
1169 if (bn >= bmp->bm_len || max > bmp->bm_len)
1170 return (-EINVAL);
1172 if (*vp->bmv_val) {
1173 bitmap_stats.bs_set++;
1174 bitmap_stats.bs_set_bits += vp->bmv_len;
1175 } else {
1176 bitmap_stats.bs_unset++;
1177 bitmap_stats.bs_unset_bits += vp->bmv_len;
1180 do {
1181 cp = dbm_chunk_find(bmp, bn);
1182 if (!cp)
1183 return (-ERANGE);
1185 for (cl = cp->c_off + cp->c_clen; bn < cl && bn < max; bn++) {
1186 rv = dbmp_set(cp, bn, vp->bmv_val);
1187 if (rv != 0)
1188 return (rv);
1190 } while (bn < max);
1192 return (0);
1197 * dbmp_getval
1199 * Get a range of bits in the bitmap specified by the
1200 * vector.
1202 static int
1203 dbmp_getval(dbitmap_t *bmp, bm_iovec_t *vp)
1205 uint_t cnt;
1206 uint_t *ip;
1207 int rv;
1208 u_quad_t cl;
1209 u_quad_t bn;
1210 u_quad_t max;
1211 dbmap_chunk_t *cp;
1213 bn = vp->bmv_base;
1214 max = bn + vp->bmv_len;
1215 if (bn >= bmp->bm_len || max > bmp->bm_len)
1216 return (-EINVAL);
1218 bitmap_stats.bs_get++;
1219 bitmap_stats.bs_get_bits += 1;
1221 cnt = 0;
1222 ip = vp->bmv_val;
1223 *ip = 0;
1224 do {
1225 cp = dbm_chunk_find(bmp, bn);
1226 if (!cp)
1227 return (-ERANGE);
1229 for (cl = cp->c_off + cp->c_clen; bn < cl && bn < max; bn++) {
1230 rv = dbmp_get(cp, bn);
1231 if (rv < 0)
1232 return (rv);
1234 *ip |= rv << cnt;
1235 if (++cnt >= BMAP_BPW) {
1236 *++ip = 0;
1237 cnt = 0;
1240 } while (bn < max);
1242 return (0);
1247 * dbyte_apply_ifset
1249 * Apply the function on the set bits of the specified word.
1251 static int
1252 dbyte_apply_ifset(dbitmap_t *bmp, u_quad_t off, uint_t b, int(*fp)(),
1253 void *arg)
1255 int bmd;
1256 int rv;
1257 u_quad_t l;
1259 rv = 0;
1260 l = dbmp_getlen(bmp);
1261 bmd = dbmp2bmd(bmp);
1262 for (; b && off < l; off++) {
1263 if (b & 1) {
1264 bitmap_stats.bs_set_applied++;
1266 if ((rv = (*fp)(bmd, off, arg)))
1267 break;
1269 b >>= 1;
1272 return (rv);
1277 * dbm_chunk_apply_ifset
1279 * Apply the function on the set bits of the specified chunk.
1281 static int
1282 dbm_chunk_apply_ifset(dbitmap_t *bmp, dbmap_chunk_t *cp, int(*fp)(),
1283 void *arg)
1285 int rv;
1286 uint_t *bp;
1287 uint_t i, m;
1288 u_quad_t q;
1290 rv = 0;
1291 bp = cp->c_bmp;
1292 q = cp->c_off;
1293 m = cp->c_mlen / BMAP_WSIZE;
1294 for (i = 0; i < m; q += BMAP_BPW, bp++, i++)
1295 if (*bp) {
1296 rv = dbyte_apply_ifset(bmp, q, *bp, fp, arg);
1297 if (rv != 0)
1298 break;
1301 return (rv);
1306 * swfile_trunc
1308 * Truncate the rest of the swap file.
1310 static int
1311 swfile_trunc(int fd)
1313 int rv;
1314 off_t off;
1317 * Get the current offset and truncate whatever is
1318 * after this point.
1320 rv = 0;
1321 if ((off = lseek(fd, 0, SEEK_CUR)) < 0)
1322 rv = -1;
1323 else if (ftruncate(fd, off) != 0)
1324 rv = -1;
1326 return (rv);
1331 * swfile_init
1333 * Initialize the swap file. The necessary disk space is
1334 * reserved by writing to the swap file for swapping the
1335 * chunks in/out of the file.
1337 static int
1338 swfile_init(int fd, u_quad_t len, int set)
1340 u_quad_t i, n;
1341 uint_t cl, ml;
1342 uint_t buf[BMAP_CHUNK_WORDS];
1344 (void) memset(buf, set ? 0xff : 0x00, BMAP_CHUNK_BYTES);
1345 n = len / BMAP_CHUNK_BITS;
1346 for (i = 0; i < n; i++)
1347 if (write(fd, buf, BMAP_CHUNK_BYTES) != BMAP_CHUNK_BYTES)
1348 return (-1);
1350 cl = (uint_t)(len % BMAP_CHUNK_BITS);
1351 ml = MEM_LEN(cl);
1352 if (write(fd, buf, ml) != ml)
1353 return (-1);
1355 return (swfile_trunc(fd));
1360 * dbm_alloc
1362 * Allocate a bit map and return a handle to it.
1364 * The swap file is created if it does not exist.
1365 * The file is truncated if it exists and is larger
1366 * than needed amount.
1368 * The hash table and LRU list are empty at this point.
1369 * They are allocated and/or loaded on-demand.
1372 dbm_alloc(char *fname, u_quad_t len, int set)
1374 int fd;
1375 int bmd;
1376 dbitmap_t *bmp;
1378 if (!fname || !*fname || !len)
1379 return (-1);
1382 * When allocating bitmap, make sure there is enough
1383 * disk space by allocating needed disk space, for
1384 * writing back the dirty chunks when swaping them out.
1386 bmd = dbmd_alloc();
1387 if (bmd < 0)
1388 return (bmd);
1390 bmp = bmd2dbmp(bmd);
1391 if ((fd = open(fname, O_RDWR|O_CREAT, 0600)) < 0)
1392 bmd = -1;
1393 else if (swfile_init(fd, len, set) < 0) {
1394 bmd = -1;
1395 (void) close(fd);
1396 (void) unlink(fname);
1397 dbmd_free(bmd);
1398 bmd = -1;
1399 } else if (!(bmp->bm_fname = strdup(fname))) {
1400 (void) close(fd);
1401 (void) unlink(fname);
1402 dbmd_free(bmd);
1403 bmd = -1;
1404 } else {
1405 bitmap_stats.bs_alloc_cnt++;
1406 bitmap_stats.bs_alloc_size += len;
1408 bmp->bm_fd = fd;
1409 if (set)
1410 BMAP_SET_FLAGS(bmp, BMAP_BINIT_ONES);
1411 else
1412 BMAP_UNSET_FLAGS(bmp, BMAP_BINIT_ONES);
1413 bmp->bm_len = len;
1414 bmp->bm_ccur = 0;
1415 bmp->bm_cmax = BMAP_CHUNK_MAX;
1416 TAILQ_INIT(&bmp->bm_lru);
1417 hash_init((bmap_list_t *)bmp->bm_hash);
1420 return (bmd);
1425 * dbm_free
1427 * Free memory allocated for the bitmap and remove its swap file.
1430 dbm_free(int bmd)
1432 int rv;
1433 dbitmap_t *bmp;
1435 bmp = bmd2dbmp(bmd);
1436 if (bmp && BMAP_IS_INUSE(bmp)) {
1437 bitmap_stats.bs_free_cnt++;
1439 dbm_chunks_free(bmp);
1440 (void) close(bmp->bm_fd);
1441 (void) unlink(bmp->bm_fname);
1442 free(bmp->bm_fname);
1443 dbmd_free(bmd);
1444 rv = 0;
1445 } else
1446 rv = -1;
1448 return (rv);
1453 * dbm_getlen
1455 * Return length of the bitmap.
1457 u_quad_t
1458 dbm_getlen(int bmd)
1460 dbitmap_t *bmp;
1462 bmp = bmd2dbmp(bmd);
1463 return (dbmp_getlen(bmp));
1468 * dbm_set
1470 * Set a range of bits.
1473 dbm_set(int bmd, u_quad_t start, u_quad_t len, uint_t val)
1475 bm_io_t io;
1476 bm_iovec_t iov;
1478 iov.bmv_base = start;
1479 iov.bmv_len = len;
1480 iov.bmv_val = &val;
1481 io.bmio_iovcnt = 1;
1482 io.bmio_iov = &iov;
1484 return (dbm_setiov(bmd, &io));
1489 * dbm_getiov
1491 * Get bits specified by the array of vectors.
1494 dbm_getiov(int bmd, bm_io_t *iop)
1496 int i;
1497 int rv;
1498 bm_iovec_t *vp;
1499 dbitmap_t *bmp;
1501 if (!iop)
1502 rv = -EINVAL;
1503 else if (!(bmp = bmd2dbmp(bmd)))
1504 rv = -EINVAL;
1505 else if (iop->bmio_iovcnt <= 0)
1506 rv = -EINVAL;
1507 else {
1508 rv = 0;
1509 vp = iop->bmio_iov;
1510 for (i = 0; i < iop->bmio_iovcnt; vp++, i++) {
1511 if (!vp)
1512 return (-EINVAL);
1513 rv |= dbmp_getval(bmp, vp);
1517 return (rv);
1522 * dbm_setiov
1524 * Set bits specified by the array of vectors.
1527 dbm_setiov(int bmd, bm_io_t *iop)
1529 int i;
1530 int rv;
1531 bm_iovec_t *vp;
1532 dbitmap_t *bmp;
1534 if (!iop)
1535 rv = -EINVAL;
1536 else if (!(bmp = bmd2dbmp(bmd)))
1537 rv = -EINVAL;
1538 else if (iop->bmio_iovcnt <= 0)
1539 rv = -EINVAL;
1540 else if (!iop->bmio_iov)
1541 rv = -EINVAL;
1542 else {
1543 rv = 0;
1544 vp = iop->bmio_iov;
1545 for (i = 0; i < iop->bmio_iovcnt; vp++, i++)
1546 rv |= dbmp_setval(bmp, vp);
1549 return (rv);
1554 * dbm_apply_ifset
1556 * Call the callback function for each set bit in the bitmap and
1557 * pass the 'arg' and bit number as its argument.
1560 dbm_apply_ifset(int bmd, int(*fp)(), void *arg)
1562 int rv;
1563 u_quad_t q;
1564 dbitmap_t *bmp;
1565 dbmap_chunk_t *cp;
1567 bmp = bmd2dbmp(bmd);
1568 if (!bmp || !fp)
1569 return (-EINVAL);
1571 rv = 0;
1572 for (q = 0; q < bmp->bm_len; q += BMAP_CHUNK_BITS) {
1573 cp = dbm_chunk_find(bmp, q);
1574 if (!cp) {
1575 rv = -ERANGE;
1576 break;
1579 rv = dbm_chunk_apply_ifset(bmp, cp, fp, arg);
1580 if (rv != 0)
1581 break;
1584 return (rv);
1589 * bm_set
1591 * Set a range of bits.
1594 bm_set(int bmd, u_quad_t start, u_quad_t len, uint_t val)
1596 bm_io_t io;
1597 bm_iovec_t iov;
1599 iov.bmv_base = start;
1600 iov.bmv_len = len;
1601 iov.bmv_val = &val;
1602 io.bmio_iovcnt = 1;
1603 io.bmio_iov = &iov;
1605 return (bm_setiov(bmd, &io));
1610 * bm_get
1612 * Get a range of bits.
1615 bm_get(int bmd, u_quad_t start, u_quad_t len, uint_t *buf)
1617 bm_io_t io;
1618 bm_iovec_t iov;
1620 iov.bmv_base = start;
1621 iov.bmv_len = len;
1622 iov.bmv_val = buf;
1623 io.bmio_iovcnt = 1;
1624 io.bmio_iov = &iov;
1626 return (bm_getiov(bmd, &io));
1631 * bm_getone
1633 * Get only one bit.
1636 bm_getone(int bmd, u_quad_t bitnum)
1638 uint_t i;
1640 if (bm_get(bmd, bitnum, 1, &i) == 0)
1641 return (i ? 1 : 0);
1643 return (0);
1648 * dbm_get
1650 * Get a range of bits.
1653 dbm_get(int bmd, u_quad_t start, u_quad_t len, uint_t *buf)
1655 bm_io_t io;
1656 bm_iovec_t iov;
1658 iov.bmv_base = start;
1659 iov.bmv_len = len;
1660 iov.bmv_val = buf;
1661 io.bmio_iovcnt = 1;
1662 io.bmio_iov = &iov;
1664 return (dbm_getiov(bmd, &io));
1669 * dbm_getone
1671 * Get only one bit.
1674 dbm_getone(int bmd, u_quad_t bitnum)
1676 uint_t i;
1678 if (dbm_get(bmd, bitnum, 1, &i) == 0)
1679 return (i ? 1 : 0);
1681 return (0);