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