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 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); 398 } 399 400 401 /* 402 * bm_chunk_new 403 * 404 * Create a new chunk and keep track of memory used. 405 */ 406 static bmap_chunk_t * 407 bm_chunk_new(bitmap_t *bmp, u_quad_t bn) 408 { 409 bmap_chunk_t *cp; 410 411 bitmap_stats.bs_chunk_new++; 412 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++; 422 } 423 } 424 425 return (cp); 426 } 427 428 429 /* 430 * bm_chunk_alloc 431 * 432 * Allocate a chunk and return it. If the cache for the chunks is not 433 * fully used, a new chunk is created. 434 */ 435 static bmap_chunk_t * 436 bm_chunk_alloc(bitmap_t *bmp, u_quad_t bn) 437 { 438 bmap_chunk_t *cp; 439 440 if (bmp->bm_ccur < bmp->bm_cmax) 441 cp = bm_chunk_new(bmp, bn); 442 else 443 cp = NULL; 444 445 return (cp); 446 } 447 448 449 /* 450 * hash_free 451 * 452 * Free all chunks on the hash list. 453 */ 454 void 455 hash_free(bmap_list_t *hp) 456 { 457 bmap_chunk_t *cp; 458 459 if (!hp) 460 return; 461 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); 467 } 468 } 469 470 471 /* 472 * bm_chunks_free 473 * 474 * Release the memory allocated for the chunks. 475 */ 476 static void 477 bm_chunks_free(bmap_list_t *hp) 478 { 479 int i; 480 481 for (i = 0; i < BMAP_HASH_SIZE; hp++, i++) 482 hash_free(hp); 483 } 484 485 486 /* 487 * bm_chunk_repositions 488 * 489 * Re-position the chunk in the MRU hash table. 490 */ 491 static void 492 bm_chunk_reposition(bitmap_t *bmp, bmap_list_t *hp, bmap_chunk_t *cp) 493 { 494 if (!bmp || !hp || !cp) 495 return; 496 497 if (TAILQ_FIRST(hp) != cp) { 498 TAILQ_REMOVE(hp, cp, c_hash); 499 TAILQ_INSERT_HEAD(hp, cp, c_hash); 500 } 501 } 502 503 504 /* 505 * bm_chunk_find 506 * 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. 509 */ 510 static bmap_chunk_t * 511 bm_chunk_find(bitmap_t *bmp, u_quad_t bn) 512 { 513 int h; 514 bmap_chunk_t *cp; 515 bmap_list_t *hp; 516 517 if (!bmp) 518 return (NULL); 519 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++; 525 526 bm_chunk_reposition(bmp, hp, cp); 527 return (cp); 528 } 529 } 530 531 bitmap_stats.bs_cache_miss++; 532 533 return (bm_chunk_alloc(bmp, bn)); 534 } 535 536 537 /* 538 * bmp_setval 539 * 540 * Set a range of bits in the bitmap specified by the vector. 541 */ 542 static int 543 bmp_setval(bitmap_t *bmp, bm_iovec_t *vp) 544 { 545 int rv; 546 u_quad_t cl; 547 u_quad_t bn; 548 u_quad_t max; 549 bmap_chunk_t *cp; 550 551 bn = vp->bmv_base; 552 max = bn + vp->bmv_len; 553 if (bn >= bmp->bm_len || max > bmp->bm_len) 554 return (-EINVAL); 555 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; 562 } 563 564 do { 565 cp = bm_chunk_find(bmp, bn); 566 if (!cp) 567 return (-ERANGE); 568 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); 573 } 574 } while (bn < max); 575 576 return (0); 577 } 578 579 580 /* 581 * bmp_getval 582 * 583 * Get a range of bits in the bitmap specified by the vector. 584 */ 585 static int 586 bmp_getval(bitmap_t *bmp, bm_iovec_t *vp) 587 { 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; 595 596 bn = vp->bmv_base; 597 max = bn + vp->bmv_len; 598 if (bn >= bmp->bm_len || max > bmp->bm_len) 599 return (-EINVAL); 600 601 bitmap_stats.bs_get++; 602 bitmap_stats.bs_get_bits += 1; 603 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); 611 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); 616 617 *ip |= rv << cnt; 618 if (++cnt >= BMAP_BPW) { 619 *++ip = 0; 620 cnt = 0; 621 } 622 } 623 } while (bn < max); 624 625 return (0); 626 } 627 628 629 /* 630 * hash_init 631 * 632 * Initialize the hash table lists head. 633 */ 634 static void 635 hash_init(bmap_list_t *hp) 636 { 637 int i; 638 639 for (i = 0; i < BMAP_HASH_SIZE; hp++, i++) { 640 TAILQ_INIT(hp); 641 } 642 } 643 644 645 /* 646 * bm_alloc 647 * 648 * Allocate a bit map and return a handle to it. 649 * 650 * The hash table list are empty at this point. They are allocated 651 * on demand. 652 */ 653 int 654 bm_alloc(u_quad_t len, int set) 655 { 656 int bmd; 657 bitmap_t *bmp; 658 659 if (len == 0) 660 return (-1); 661 662 bmd = bmd_alloc(); 663 if (bmd < 0) 664 return (bmd); 665 666 bmp = bmd2bmp(bmd); 667 bitmap_stats.bs_alloc_cnt++; 668 bitmap_stats.bs_alloc_size += len; 669 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); 678 679 return (bmd); 680 } 681 682 683 /* 684 * bm_free 685 * 686 * Free memory allocated for the bitmap. 687 */ 688 int 689 bm_free(int bmd) 690 { 691 int rv; 692 bitmap_t *bmp; 693 694 bmp = bmd2bmp(bmd); 695 if (bmp && BMAP_IS_INUSE(bmp)) { 696 bitmap_stats.bs_free_cnt++; 697 698 bm_chunks_free(bmp->bm_hash); 699 bmd_free(bmd); 700 rv = 0; 701 } else 702 rv = -1; 703 704 return (rv); 705 } 706 707 708 /* 709 * bm_getiov 710 * 711 * Get bits specified by the array of vectors. 712 */ 713 int 714 bm_getiov(int bmd, bm_io_t *iop) 715 { 716 int i; 717 int rv; 718 bm_iovec_t *vp; 719 bitmap_t *bmp; 720 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); 734 } 735 } 736 737 return (rv); 738 } 739 740 741 /* 742 * bm_setiov 743 * 744 * Set bits specified by the array of vectors. 745 */ 746 int 747 bm_setiov(int bmd, bm_io_t *iop) 748 { 749 int i; 750 int rv; 751 bm_iovec_t *vp; 752 bitmap_t *bmp; 753 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); 767 } 768 769 return (rv); 770 } 771 772 773 /* 774 * bmd2dbmp 775 * 776 * Convert bitmap descriptor to bitmap pointer. 777 */ 778 static dbitmap_t * 779 bmd2dbmp(int bmd) 780 { 781 if (bmd < 0 || bmd >= BMAP_MAX) 782 return (NULL); 783 784 return (&dbitmap[bmd]); 785 } 786 787 788 /* 789 * dbmp2bmd 790 * 791 * Convert bitmap pointer to bitmap descriptor. 792 */ 793 static int 794 dbmp2bmd(dbitmap_t *bmp) 795 { 796 int bmd; 797 798 bmd = bmp - dbitmap; 799 if (bmd < 0 || bmd >= BMAP_MAX) 800 bmd = -1; 801 802 return (bmd); 803 } 804 805 /* 806 * dbmd_alloc 807 * 808 * Allocate a bitmap descriptor. 809 * Sets the INUSE flag of the slot. 810 */ 811 static int 812 dbmd_alloc(void) 813 { 814 int i; 815 dbitmap_t *bmp; 816 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); 822 } 823 824 return (-1); 825 } 826 827 828 /* 829 * dbmd_free 830 * 831 * Free a bitmap descriptor. 832 * Clears the INUSE flag of the slot. 833 */ 834 static void 835 dbmd_free(int bmd) 836 { 837 dbitmap_t *bmp; 838 839 bmp = bmd2dbmp(bmd); 840 if (bmp) 841 BMAP_UNSET_FLAGS(bmp, BMAP_INUSE); 842 } 843 844 845 /* 846 * dbmp_set 847 * 848 * Generic function to set bit in a chunk. This can 849 * set or unset the specified bit. 850 */ 851 static inline int 852 dbmp_set(dbmap_chunk_t *cp, u_quad_t bn, uint_t *vp) 853 { 854 int rv; 855 uint_t mask; 856 uint_t *ip; 857 uint_t v; 858 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; 869 870 return (rv); 871 } 872 873 874 /* 875 * dbmp_getlen 876 * 877 * Get length of the bitmap. 878 */ 879 static u_quad_t 880 dbmp_getlen(dbitmap_t *bmp) 881 { 882 return (bmp ? bmp->bm_len : 0LL); 883 } 884 885 886 /* 887 * dbmp_get 888 * 889 * Generic function to get bit in a chunk. 890 */ 891 static inline int 892 dbmp_get(dbmap_chunk_t *cp, u_quad_t bn) 893 { 894 int rv; 895 uint_t bit; 896 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; 903 904 return (rv); 905 } 906 907 908 /* 909 * dbm_chunk_seek 910 * 911 * Seek in the file where the chunk is saved or should be saved. 912 */ 913 static int 914 dbm_chunk_seek(dbitmap_t *bmp, u_quad_t bn) 915 { 916 int rv; 917 off_t off; 918 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; 924 } 925 926 return (rv); 927 } 928 929 930 /* 931 * dbm_chunk_flush 932 * 933 * Save a chunk to file. 934 */ 935 static int 936 dbm_chunk_flush(dbitmap_t *bmp, dbmap_chunk_t *cp) 937 { 938 int rv; 939 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; 949 950 return (rv); 951 } 952 953 954 /* 955 * dbm_chunk_load 956 * 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. 962 * 963 * The new chunk is positioned in the LRU and hash table 964 * after its data is ready. 965 */ 966 static dbmap_chunk_t * 967 dbm_chunk_load(dbitmap_t *bmp, dbmap_chunk_t *cp, u_quad_t bn, int new) 968 { 969 int h; 970 u_quad_t off, l; 971 uint_t cl, ml; 972 dbmap_list_t *hp; 973 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); 982 } 983 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; 994 } 995 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; 1005 } 1006 1007 return (cp); 1008 } 1009 1010 1011 /* 1012 * dbm_chunk_new 1013 * 1014 * Create a new chunk and keep track of memory used. 1015 */ 1016 static dbmap_chunk_t * 1017 dbm_chunk_new(dbitmap_t *bmp, u_quad_t bn) 1018 { 1019 dbmap_chunk_t *cp; 1020 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++; 1034 } 1035 1036 return (cp); 1037 } 1038 1039 1040 /* 1041 * dbm_chunk_alloc 1042 * 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. 1047 */ 1048 static dbmap_chunk_t * 1049 dbm_chunk_alloc(dbitmap_t *bmp, u_quad_t bn) 1050 { 1051 int h; 1052 dbmap_list_t *hp; 1053 dbmap_chunk_t *cp; 1054 1055 if (bmp->bm_ccur < bmp->bm_cmax) 1056 return (dbm_chunk_new(bmp, bn)); 1057 1058 bitmap_stats.bs_chunk_reclaim++; 1059 1060 cp = TAILQ_FIRST(&bmp->bm_lru); 1061 if (BMAP_CIS_DIRTY(cp)) 1062 (void) dbm_chunk_flush(bmp, cp); 1063 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)); 1069 } 1070 1071 1072 /* 1073 * dbm_chunks_free 1074 * 1075 * Release the memory allocated for the chunks. 1076 */ 1077 static void 1078 dbm_chunks_free(dbitmap_t *bmp) 1079 { 1080 dbmap_list_t *headp; 1081 dbmap_chunk_t *cp; 1082 1083 if (!bmp) 1084 return; 1085 1086 headp = &bmp->bm_lru; 1087 if (!headp) 1088 return; 1089 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); 1095 } 1096 } 1097 1098 1099 /* 1100 * dbm_chunk_reposition 1101 * 1102 * Re-position the chunk in the LRU and the hash table. 1103 */ 1104 static void 1105 dbm_chunk_reposition(dbitmap_t *bmp, dbmap_list_t *hp, dbmap_chunk_t *cp) 1106 { 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); 1113 } 1114 } 1115 } 1116 1117 1118 /* 1119 * dbm_chunk_find 1120 * 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. 1124 */ 1125 static dbmap_chunk_t * 1126 dbm_chunk_find(dbitmap_t *bmp, u_quad_t bn) 1127 { 1128 int h; 1129 dbmap_chunk_t *cp; 1130 dbmap_list_t *hp; 1131 1132 if (!bmp) 1133 return (NULL); 1134 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++; 1140 1141 dbm_chunk_reposition(bmp, hp, cp); 1142 return (cp); 1143 } 1144 } 1145 1146 bitmap_stats.bs_cache_miss++; 1147 1148 return (dbm_chunk_alloc(bmp, bn)); 1149 } 1150 1151 1152 /* 1153 * dbmp_setval 1154 * 1155 * Set a range of bits in the bitmap specified by the 1156 * vector. 1157 */ 1158 static int 1159 dbmp_setval(dbitmap_t *bmp, bm_iovec_t *vp) 1160 { 1161 int rv; 1162 u_quad_t cl; 1163 u_quad_t bn; 1164 u_quad_t max; 1165 dbmap_chunk_t *cp; 1166 1167 bn = vp->bmv_base; 1168 max = bn + vp->bmv_len; 1169 if (bn >= bmp->bm_len || max > bmp->bm_len) 1170 return (-EINVAL); 1171 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; 1178 } 1179 1180 do { 1181 cp = dbm_chunk_find(bmp, bn); 1182 if (!cp) 1183 return (-ERANGE); 1184 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); 1189 } 1190 } while (bn < max); 1191 1192 return (0); 1193 } 1194 1195 1196 /* 1197 * dbmp_getval 1198 * 1199 * Get a range of bits in the bitmap specified by the 1200 * vector. 1201 */ 1202 static int 1203 dbmp_getval(dbitmap_t *bmp, bm_iovec_t *vp) 1204 { 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; 1212 1213 bn = vp->bmv_base; 1214 max = bn + vp->bmv_len; 1215 if (bn >= bmp->bm_len || max > bmp->bm_len) 1216 return (-EINVAL); 1217 1218 bitmap_stats.bs_get++; 1219 bitmap_stats.bs_get_bits += 1; 1220 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); 1228 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); 1233 1234 *ip |= rv << cnt; 1235 if (++cnt >= BMAP_BPW) { 1236 *++ip = 0; 1237 cnt = 0; 1238 } 1239 } 1240 } while (bn < max); 1241 1242 return (0); 1243 } 1244 1245 1246 /* 1247 * dbyte_apply_ifset 1248 * 1249 * Apply the function on the set bits of the specified word. 1250 */ 1251 static int 1252 dbyte_apply_ifset(dbitmap_t *bmp, u_quad_t off, uint_t b, int(*fp)(), 1253 void *arg) 1254 { 1255 int bmd; 1256 int rv; 1257 u_quad_t l; 1258 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++; 1265 1266 if ((rv = (*fp)(bmd, off, arg))) 1267 break; 1268 } 1269 b >>= 1; 1270 } 1271 1272 return (rv); 1273 } 1274 1275 1276 /* 1277 * dbm_chunk_apply_ifset 1278 * 1279 * Apply the function on the set bits of the specified chunk. 1280 */ 1281 static int 1282 dbm_chunk_apply_ifset(dbitmap_t *bmp, dbmap_chunk_t *cp, int(*fp)(), 1283 void *arg) 1284 { 1285 int rv; 1286 uint_t *bp; 1287 uint_t i, m; 1288 u_quad_t q; 1289 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; 1299 } 1300 1301 return (rv); 1302 } 1303 1304 1305 /* 1306 * swfile_trunc 1307 * 1308 * Truncate the rest of the swap file. 1309 */ 1310 static int 1311 swfile_trunc(int fd) 1312 { 1313 int rv; 1314 off_t off; 1315 1316 /* 1317 * Get the current offset and truncate whatever is 1318 * after this point. 1319 */ 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; 1325 1326 return (rv); 1327 } 1328 1329 1330 /* 1331 * swfile_init 1332 * 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. 1336 */ 1337 static int 1338 swfile_init(int fd, u_quad_t len, int set) 1339 { 1340 u_quad_t i, n; 1341 uint_t cl, ml; 1342 uint_t buf[BMAP_CHUNK_WORDS]; 1343 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); 1349 1350 cl = (uint_t)(len % BMAP_CHUNK_BITS); 1351 ml = MEM_LEN(cl); 1352 if (write(fd, buf, ml) != ml) 1353 return (-1); 1354 1355 return (swfile_trunc(fd)); 1356 } 1357 1358 1359 /* 1360 * dbm_alloc 1361 * 1362 * Allocate a bit map and return a handle to it. 1363 * 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. 1367 * 1368 * The hash table and LRU list are empty at this point. 1369 * They are allocated and/or loaded on-demand. 1370 */ 1371 int 1372 dbm_alloc(char *fname, u_quad_t len, int set) 1373 { 1374 int fd; 1375 int bmd; 1376 dbitmap_t *bmp; 1377 1378 if (!fname || !*fname || !len) 1379 return (-1); 1380 1381 /* 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. 1385 */ 1386 bmd = dbmd_alloc(); 1387 if (bmd < 0) 1388 return (bmd); 1389 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; 1407 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); 1418 } 1419 1420 return (bmd); 1421 } 1422 1423 1424 /* 1425 * dbm_free 1426 * 1427 * Free memory allocated for the bitmap and remove its swap file. 1428 */ 1429 int 1430 dbm_free(int bmd) 1431 { 1432 int rv; 1433 dbitmap_t *bmp; 1434 1435 bmp = bmd2dbmp(bmd); 1436 if (bmp && BMAP_IS_INUSE(bmp)) { 1437 bitmap_stats.bs_free_cnt++; 1438 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; 1447 1448 return (rv); 1449 } 1450 1451 1452 /* 1453 * dbm_getlen 1454 * 1455 * Return length of the bitmap. 1456 */ 1457 u_quad_t 1458 dbm_getlen(int bmd) 1459 { 1460 dbitmap_t *bmp; 1461 1462 bmp = bmd2dbmp(bmd); 1463 return (dbmp_getlen(bmp)); 1464 } 1465 1466 1467 /* 1468 * dbm_set 1469 * 1470 * Set a range of bits. 1471 */ 1472 int 1473 dbm_set(int bmd, u_quad_t start, u_quad_t len, uint_t val) 1474 { 1475 bm_io_t io; 1476 bm_iovec_t iov; 1477 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; 1483 1484 return (dbm_setiov(bmd, &io)); 1485 } 1486 1487 1488 /* 1489 * dbm_getiov 1490 * 1491 * Get bits specified by the array of vectors. 1492 */ 1493 int 1494 dbm_getiov(int bmd, bm_io_t *iop) 1495 { 1496 int i; 1497 int rv; 1498 bm_iovec_t *vp; 1499 dbitmap_t *bmp; 1500 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); 1514 } 1515 } 1516 1517 return (rv); 1518 } 1519 1520 1521 /* 1522 * dbm_setiov 1523 * 1524 * Set bits specified by the array of vectors. 1525 */ 1526 int 1527 dbm_setiov(int bmd, bm_io_t *iop) 1528 { 1529 int i; 1530 int rv; 1531 bm_iovec_t *vp; 1532 dbitmap_t *bmp; 1533 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); 1547 } 1548 1549 return (rv); 1550 } 1551 1552 1553 /* 1554 * dbm_apply_ifset 1555 * 1556 * Call the callback function for each set bit in the bitmap and 1557 * pass the 'arg' and bit number as its argument. 1558 */ 1559 int 1560 dbm_apply_ifset(int bmd, int(*fp)(), void *arg) 1561 { 1562 int rv; 1563 u_quad_t q; 1564 dbitmap_t *bmp; 1565 dbmap_chunk_t *cp; 1566 1567 bmp = bmd2dbmp(bmd); 1568 if (!bmp || !fp) 1569 return (-EINVAL); 1570 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; 1577 } 1578 1579 rv = dbm_chunk_apply_ifset(bmp, cp, fp, arg); 1580 if (rv != 0) 1581 break; 1582 } 1583 1584 return (rv); 1585 } 1586 1587 1588 /* 1589 * bm_set 1590 * 1591 * Set a range of bits. 1592 */ 1593 int 1594 bm_set(int bmd, u_quad_t start, u_quad_t len, uint_t val) 1595 { 1596 bm_io_t io; 1597 bm_iovec_t iov; 1598 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; 1604 1605 return (bm_setiov(bmd, &io)); 1606 } 1607 1608 1609 /* 1610 * bm_get 1611 * 1612 * Get a range of bits. 1613 */ 1614 int 1615 bm_get(int bmd, u_quad_t start, u_quad_t len, uint_t *buf) 1616 { 1617 bm_io_t io; 1618 bm_iovec_t iov; 1619 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; 1625 1626 return (bm_getiov(bmd, &io)); 1627 } 1628 1629 1630 /* 1631 * bm_getone 1632 * 1633 * Get only one bit. 1634 */ 1635 int 1636 bm_getone(int bmd, u_quad_t bitnum) 1637 { 1638 uint_t i; 1639 1640 if (bm_get(bmd, bitnum, 1, &i) == 0) 1641 return (i ? 1 : 0); 1642 1643 return (0); 1644 } 1645 1646 1647 /* 1648 * dbm_get 1649 * 1650 * Get a range of bits. 1651 */ 1652 int 1653 dbm_get(int bmd, u_quad_t start, u_quad_t len, uint_t *buf) 1654 { 1655 bm_io_t io; 1656 bm_iovec_t iov; 1657 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; 1663 1664 return (dbm_getiov(bmd, &io)); 1665 } 1666 1667 1668 /* 1669 * dbm_getone 1670 * 1671 * Get only one bit. 1672 */ 1673 int 1674 dbm_getone(int bmd, u_quad_t bitnum) 1675 { 1676 uint_t i; 1677 1678 if (dbm_get(bmd, bitnum, 1, &i) == 0) 1679 return (i ? 1 : 0); 1680 1681 return (0); 1682 } 1683