2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
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
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
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
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>
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.
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)
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
116 #define ROUNDUP(n, d) (((n) + (d) - 1) / (d))
117 #define MEM_LEN(l) (ROUNDUP((l), BMAP_BPW) * BMAP_WSIZE)
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
157 typedef struct dbmap_chunk
{
158 TAILQ_ENTRY(dbmap_chunk
) c_hash
;
159 TAILQ_ENTRY(dbmap_chunk
) c_lru
;
168 TAILQ_HEAD(dbmap_list
, dbmap_chunk
);
169 typedef struct dbmap_list dbmap_list_t
;
172 typedef struct dbitmap
{
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 */
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
;
210 TAILQ_HEAD(bmap_list
, bmap_chunk
);
211 typedef struct bmap_list bmap_list_t
;
214 typedef struct bitmap
{
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 */
224 * Statistics gathering structure.
226 typedef struct bitmap_stats
{
227 ulong_t bs_alloc_cnt
;
228 ulong_t bs_alloc_size
;
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
;
238 u_quad_t bs_get_bits
;
240 u_quad_t bs_set_bits
;
242 u_quad_t bs_unset_bits
;
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
;
262 * Convert bitmap descriptor to bitmap pointer.
267 if (bmd
< 0 || bmd
>= BMAP_MAX
)
270 return (&bitmap
[bmd
]);
277 * Allocate a bitmap descriptor. Sets the INUSE flag of the slot.
286 for (i
= 0; i
< BMAP_MAX
; bmp
++, i
++)
287 if (!BMAP_IS_INUSE(bmp
)) {
288 BMAP_SET_FLAGS(bmp
, BMAP_INUSE
);
299 * Free a bitmap descriptor. Clears the INUSE flag of the slot.
308 BMAP_UNSET_FLAGS(bmp
, BMAP_INUSE
);
315 * Generic function to set bit in a chunk. This can set or unset the
319 bmp_set(bmap_chunk_t
*cp
, u_quad_t bn
, uint_t
*vp
)
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
;
343 * Generic function to get bit in a chunk.
346 bmp_get(bmap_chunk_t
*cp
, u_quad_t bn
)
352 if (bn
< cp
->c_clen
) {
353 bit
= 1 <<(bn
& BMAP_BPW_MASK
);
354 rv
= (cp
->c_bmp
[bn
>> BMAP_BPW_SHIFT
] & bit
) != 0;
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
)
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
;
385 if (BMAP_IS_INIT_ONES(bmp
))
386 (void) memset(cp
->c_bmp
, 0xff, ml
);
388 (void) memset(cp
->c_bmp
, 0x00, ml
);
391 hp
= &bmp
->bm_hash
[h
];
393 TAILQ_INSERT_HEAD(hp
, cp
, c_hash
);
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
)
411 bitmap_stats
.bs_chunk_new
++;
413 cp
= ndmp_malloc(sizeof (bmap_chunk_t
));
415 cp
->c_bmp
= ndmp_malloc(sizeof (uint_t
) * BMAP_CHUNK_WORDS
);
420 (void) bm_chunk_setup(bmp
, cp
, bn
);
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
)
440 if (bmp
->bm_ccur
< bmp
->bm_cmax
)
441 cp
= bm_chunk_new(bmp
, bn
);
452 * Free all chunks on the hash list.
455 hash_free(bmap_list_t
*hp
)
462 while (!TAILQ_EMPTY(hp
)) {
463 cp
= TAILQ_FIRST(hp
);
464 TAILQ_REMOVE(hp
, cp
, c_hash
);
474 * Release the memory allocated for the chunks.
477 bm_chunks_free(bmap_list_t
*hp
)
481 for (i
= 0; i
< BMAP_HASH_SIZE
; hp
++, i
++)
487 * bm_chunk_repositions
489 * Re-position the chunk in the MRU hash table.
492 bm_chunk_reposition(bitmap_t
*bmp
, bmap_list_t
*hp
, bmap_chunk_t
*cp
)
494 if (!bmp
|| !hp
|| !cp
)
497 if (TAILQ_FIRST(hp
) != cp
) {
498 TAILQ_REMOVE(hp
, cp
, c_hash
);
499 TAILQ_INSERT_HEAD(hp
, cp
, c_hash
);
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
)
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
);
531 bitmap_stats
.bs_cache_miss
++;
533 return (bm_chunk_alloc(bmp
, bn
));
540 * Set a range of bits in the bitmap specified by the vector.
543 bmp_setval(bitmap_t
*bmp
, bm_iovec_t
*vp
)
552 max
= bn
+ vp
->bmv_len
;
553 if (bn
>= bmp
->bm_len
|| max
> bmp
->bm_len
)
557 bitmap_stats
.bs_set
++;
558 bitmap_stats
.bs_set_bits
+= vp
->bmv_len
;
560 bitmap_stats
.bs_unset
++;
561 bitmap_stats
.bs_unset_bits
+= vp
->bmv_len
;
565 cp
= bm_chunk_find(bmp
, bn
);
569 for (cl
= cp
->c_off
+ cp
->c_clen
; bn
< cl
&& bn
< max
; bn
++) {
570 rv
= bmp_set(cp
, bn
, vp
->bmv_val
);
583 * Get a range of bits in the bitmap specified by the vector.
586 bmp_getval(bitmap_t
*bmp
, bm_iovec_t
*vp
)
597 max
= bn
+ vp
->bmv_len
;
598 if (bn
>= bmp
->bm_len
|| max
> bmp
->bm_len
)
601 bitmap_stats
.bs_get
++;
602 bitmap_stats
.bs_get_bits
+= 1;
608 cp
= bm_chunk_find(bmp
, bn
);
612 for (cl
= cp
->c_off
+ cp
->c_clen
; bn
< cl
&& bn
< max
; bn
++) {
613 rv
= bmp_get(cp
, bn
);
618 if (++cnt
>= BMAP_BPW
) {
632 * Initialize the hash table lists head.
635 hash_init(bmap_list_t
*hp
)
639 for (i
= 0; i
< BMAP_HASH_SIZE
; hp
++, i
++) {
648 * Allocate a bit map and return a handle to it.
650 * The hash table list are empty at this point. They are allocated
654 bm_alloc(u_quad_t len
, int set
)
667 bitmap_stats
.bs_alloc_cnt
++;
668 bitmap_stats
.bs_alloc_size
+= len
;
671 BMAP_SET_FLAGS(bmp
, BMAP_BINIT_ONES
);
673 BMAP_UNSET_FLAGS(bmp
, BMAP_BINIT_ONES
);
676 bmp
->bm_cmax
= BMAP_CHUNK_MAX
;
677 hash_init(bmp
->bm_hash
);
686 * Free memory allocated for the bitmap.
695 if (bmp
&& BMAP_IS_INUSE(bmp
)) {
696 bitmap_stats
.bs_free_cnt
++;
698 bm_chunks_free(bmp
->bm_hash
);
711 * Get bits specified by the array of vectors.
714 bm_getiov(int bmd
, bm_io_t
*iop
)
723 else if (!(bmp
= bmd2bmp(bmd
)))
725 else if (iop
->bmio_iovcnt
<= 0)
730 for (i
= 0; i
< iop
->bmio_iovcnt
; vp
++, i
++) {
733 rv
|= bmp_getval(bmp
, vp
);
744 * Set bits specified by the array of vectors.
747 bm_setiov(int bmd
, bm_io_t
*iop
)
756 else if (!(bmp
= bmd2bmp(bmd
)))
758 else if (iop
->bmio_iovcnt
<= 0)
760 else if (!iop
->bmio_iov
)
765 for (i
= 0; i
< iop
->bmio_iovcnt
; vp
++, i
++)
766 rv
|= bmp_setval(bmp
, vp
);
776 * Convert bitmap descriptor to bitmap pointer.
781 if (bmd
< 0 || bmd
>= BMAP_MAX
)
784 return (&dbitmap
[bmd
]);
791 * Convert bitmap pointer to bitmap descriptor.
794 dbmp2bmd(dbitmap_t
*bmp
)
799 if (bmd
< 0 || bmd
>= BMAP_MAX
)
808 * Allocate a bitmap descriptor.
809 * Sets the INUSE flag of the slot.
818 for (i
= 0; i
< BMAP_MAX
; bmp
++, i
++)
819 if (!BMAP_IS_INUSE(bmp
)) {
820 BMAP_SET_FLAGS(bmp
, BMAP_INUSE
);
831 * Free a bitmap descriptor.
832 * Clears the INUSE flag of the slot.
841 BMAP_UNSET_FLAGS(bmp
, BMAP_INUSE
);
848 * Generic function to set bit in a chunk. This can
849 * set or unset the specified bit.
852 dbmp_set(dbmap_chunk_t
*cp
, u_quad_t bn
, uint_t
*vp
)
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
;
877 * Get length of the bitmap.
880 dbmp_getlen(dbitmap_t
*bmp
)
882 return (bmp
? bmp
->bm_len
: 0LL);
889 * Generic function to get bit in a chunk.
892 dbmp_get(dbmap_chunk_t
*cp
, u_quad_t bn
)
898 if (bn
< cp
->c_clen
) {
899 bit
= 1 <<(bn
& BMAP_BPW_MASK
);
900 rv
= (cp
->c_bmp
[bn
>> BMAP_BPW_SHIFT
] & bit
) != 0;
911 * Seek in the file where the chunk is saved or should be saved.
914 dbm_chunk_seek(dbitmap_t
*bmp
, u_quad_t bn
)
922 off
= BMAP_CHUNK_NO(bn
) * BMAP_CHUNK_BYTES
;
923 rv
= (lseek(bmp
->bm_fd
, off
, SEEK_SET
) != off
) ? -1 : 0;
933 * Save a chunk to file.
936 dbm_chunk_flush(dbitmap_t
*bmp
, dbmap_chunk_t
*cp
)
940 bitmap_stats
.bs_chunk_flush
++;
943 else if (dbm_chunk_seek(bmp
, cp
->c_off
) != 0)
945 else if (write(bmp
->bm_fd
, cp
->c_bmp
, cp
->c_mlen
) != cp
->c_mlen
)
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
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)
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
;
984 if (new == BMAP_NEW_CHUNK
) {
985 if (BMAP_IS_INIT_ONES(bmp
))
986 (void) memset(cp
->c_bmp
, 0xff, ml
);
988 (void) memset(cp
->c_bmp
, 0x00, ml
);
989 } else { /* BMAP_OLD_CHUNK */
990 if (dbm_chunk_seek(bmp
, bn
) != 0)
992 else if (read(bmp
->bm_fd
, cp
->c_bmp
, ml
) != ml
)
997 TAILQ_INSERT_TAIL(&bmp
->bm_lru
, cp
, c_lru
);
999 hp
= &bmp
->bm_hash
[h
];
1000 TAILQ_INSERT_HEAD(hp
, cp
, c_hash
);
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
)
1021 bitmap_stats
.bs_chunk_new
++;
1022 cp
= ndmp_malloc(sizeof (dbmap_chunk_t
));
1024 cp
->c_bmp
= ndmp_malloc(sizeof (uint_t
) * BMAP_CHUNK_WORDS
);
1028 } else if (!dbm_chunk_load(bmp
, cp
, bn
, BMAP_NEW_CHUNK
)) {
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
)
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
));
1075 * Release the memory allocated for the chunks.
1078 dbm_chunks_free(dbitmap_t
*bmp
)
1080 dbmap_list_t
*headp
;
1086 headp
= &bmp
->bm_lru
;
1090 while (!TAILQ_EMPTY(headp
)) {
1091 cp
= TAILQ_FIRST(headp
);
1092 TAILQ_REMOVE(headp
, cp
, c_lru
);
1100 * dbm_chunk_reposition
1102 * Re-position the chunk in the LRU and the hash table.
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
);
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
)
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
);
1146 bitmap_stats
.bs_cache_miss
++;
1148 return (dbm_chunk_alloc(bmp
, bn
));
1155 * Set a range of bits in the bitmap specified by the
1159 dbmp_setval(dbitmap_t
*bmp
, bm_iovec_t
*vp
)
1168 max
= bn
+ vp
->bmv_len
;
1169 if (bn
>= bmp
->bm_len
|| max
> bmp
->bm_len
)
1173 bitmap_stats
.bs_set
++;
1174 bitmap_stats
.bs_set_bits
+= vp
->bmv_len
;
1176 bitmap_stats
.bs_unset
++;
1177 bitmap_stats
.bs_unset_bits
+= vp
->bmv_len
;
1181 cp
= dbm_chunk_find(bmp
, bn
);
1185 for (cl
= cp
->c_off
+ cp
->c_clen
; bn
< cl
&& bn
< max
; bn
++) {
1186 rv
= dbmp_set(cp
, bn
, vp
->bmv_val
);
1199 * Get a range of bits in the bitmap specified by the
1203 dbmp_getval(dbitmap_t
*bmp
, bm_iovec_t
*vp
)
1214 max
= bn
+ vp
->bmv_len
;
1215 if (bn
>= bmp
->bm_len
|| max
> bmp
->bm_len
)
1218 bitmap_stats
.bs_get
++;
1219 bitmap_stats
.bs_get_bits
+= 1;
1225 cp
= dbm_chunk_find(bmp
, bn
);
1229 for (cl
= cp
->c_off
+ cp
->c_clen
; bn
< cl
&& bn
< max
; bn
++) {
1230 rv
= dbmp_get(cp
, bn
);
1235 if (++cnt
>= BMAP_BPW
) {
1249 * Apply the function on the set bits of the specified word.
1252 dbyte_apply_ifset(dbitmap_t
*bmp
, u_quad_t off
, uint_t b
, int(*fp
)(),
1260 l
= dbmp_getlen(bmp
);
1261 bmd
= dbmp2bmd(bmp
);
1262 for (; b
&& off
< l
; off
++) {
1264 bitmap_stats
.bs_set_applied
++;
1266 if ((rv
= (*fp
)(bmd
, off
, arg
)))
1277 * dbm_chunk_apply_ifset
1279 * Apply the function on the set bits of the specified chunk.
1282 dbm_chunk_apply_ifset(dbitmap_t
*bmp
, dbmap_chunk_t
*cp
, int(*fp
)(),
1293 m
= cp
->c_mlen
/ BMAP_WSIZE
;
1294 for (i
= 0; i
< m
; q
+= BMAP_BPW
, bp
++, i
++)
1296 rv
= dbyte_apply_ifset(bmp
, q
, *bp
, fp
, arg
);
1308 * Truncate the rest of the swap file.
1311 swfile_trunc(int fd
)
1317 * Get the current offset and truncate whatever is
1321 if ((off
= lseek(fd
, 0, SEEK_CUR
)) < 0)
1323 else if (ftruncate(fd
, off
) != 0)
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.
1338 swfile_init(int fd
, u_quad_t len
, int set
)
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
)
1350 cl
= (uint_t
)(len
% BMAP_CHUNK_BITS
);
1352 if (write(fd
, buf
, ml
) != ml
)
1355 return (swfile_trunc(fd
));
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
)
1378 if (!fname
|| !*fname
|| !len
)
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.
1390 bmp
= bmd2dbmp(bmd
);
1391 if ((fd
= open(fname
, O_RDWR
|O_CREAT
, 0600)) < 0)
1393 else if (swfile_init(fd
, len
, set
) < 0) {
1396 (void) unlink(fname
);
1399 } else if (!(bmp
->bm_fname
= strdup(fname
))) {
1401 (void) unlink(fname
);
1405 bitmap_stats
.bs_alloc_cnt
++;
1406 bitmap_stats
.bs_alloc_size
+= len
;
1410 BMAP_SET_FLAGS(bmp
, BMAP_BINIT_ONES
);
1412 BMAP_UNSET_FLAGS(bmp
, BMAP_BINIT_ONES
);
1415 bmp
->bm_cmax
= BMAP_CHUNK_MAX
;
1416 TAILQ_INIT(&bmp
->bm_lru
);
1417 hash_init((bmap_list_t
*)bmp
->bm_hash
);
1427 * Free memory allocated for the bitmap and remove its swap file.
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
);
1455 * Return length of the bitmap.
1462 bmp
= bmd2dbmp(bmd
);
1463 return (dbmp_getlen(bmp
));
1470 * Set a range of bits.
1473 dbm_set(int bmd
, u_quad_t start
, u_quad_t len
, uint_t val
)
1478 iov
.bmv_base
= start
;
1484 return (dbm_setiov(bmd
, &io
));
1491 * Get bits specified by the array of vectors.
1494 dbm_getiov(int bmd
, bm_io_t
*iop
)
1503 else if (!(bmp
= bmd2dbmp(bmd
)))
1505 else if (iop
->bmio_iovcnt
<= 0)
1510 for (i
= 0; i
< iop
->bmio_iovcnt
; vp
++, i
++) {
1513 rv
|= dbmp_getval(bmp
, vp
);
1524 * Set bits specified by the array of vectors.
1527 dbm_setiov(int bmd
, bm_io_t
*iop
)
1536 else if (!(bmp
= bmd2dbmp(bmd
)))
1538 else if (iop
->bmio_iovcnt
<= 0)
1540 else if (!iop
->bmio_iov
)
1545 for (i
= 0; i
< iop
->bmio_iovcnt
; vp
++, i
++)
1546 rv
|= dbmp_setval(bmp
, vp
);
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
)
1567 bmp
= bmd2dbmp(bmd
);
1572 for (q
= 0; q
< bmp
->bm_len
; q
+= BMAP_CHUNK_BITS
) {
1573 cp
= dbm_chunk_find(bmp
, q
);
1579 rv
= dbm_chunk_apply_ifset(bmp
, cp
, fp
, arg
);
1591 * Set a range of bits.
1594 bm_set(int bmd
, u_quad_t start
, u_quad_t len
, uint_t val
)
1599 iov
.bmv_base
= start
;
1605 return (bm_setiov(bmd
, &io
));
1612 * Get a range of bits.
1615 bm_get(int bmd
, u_quad_t start
, u_quad_t len
, uint_t
*buf
)
1620 iov
.bmv_base
= start
;
1626 return (bm_getiov(bmd
, &io
));
1636 bm_getone(int bmd
, u_quad_t bitnum
)
1640 if (bm_get(bmd
, bitnum
, 1, &i
) == 0)
1650 * Get a range of bits.
1653 dbm_get(int bmd
, u_quad_t start
, u_quad_t len
, uint_t
*buf
)
1658 iov
.bmv_base
= start
;
1664 return (dbm_getiov(bmd
, &io
));
1674 dbm_getone(int bmd
, u_quad_t bitnum
)
1678 if (dbm_get(bmd
, bitnum
, 1, &i
) == 0)