diff options
| author | Steve French <sfrench@us.ibm.com> | 2006-03-30 22:35:56 -0500 |
|---|---|---|
| committer | Steve French <sfrench@us.ibm.com> | 2006-03-30 22:35:56 -0500 |
| commit | d62e54abca1146981fc9f98f85ff398a113a22c2 (patch) | |
| tree | 870420dbc4c65e716dcef8a802aafdc0ef97a8b4 /lib/bitmap.c | |
| parent | fd4a0b92db6a57cba8d03efbe1cebf91f9124ce0 (diff) | |
| parent | ce362c009250340358a7221f3cdb7954cbf19c01 (diff) | |
Merge with /pub/scm/linux/kernel/git/torvalds/linux-2.6.git
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'lib/bitmap.c')
| -rw-r--r-- | lib/bitmap.c | 182 |
1 files changed, 113 insertions, 69 deletions
diff --git a/lib/bitmap.c b/lib/bitmap.c index 48e708381d44..ed2ae3b0cd06 100644 --- a/lib/bitmap.c +++ b/lib/bitmap.c | |||
| @@ -253,33 +253,18 @@ int __bitmap_subset(const unsigned long *bitmap1, | |||
| 253 | } | 253 | } |
| 254 | EXPORT_SYMBOL(__bitmap_subset); | 254 | EXPORT_SYMBOL(__bitmap_subset); |
| 255 | 255 | ||
| 256 | #if BITS_PER_LONG == 32 | ||
| 257 | int __bitmap_weight(const unsigned long *bitmap, int bits) | 256 | int __bitmap_weight(const unsigned long *bitmap, int bits) |
| 258 | { | 257 | { |
| 259 | int k, w = 0, lim = bits/BITS_PER_LONG; | 258 | int k, w = 0, lim = bits/BITS_PER_LONG; |
| 260 | 259 | ||
| 261 | for (k = 0; k < lim; k++) | 260 | for (k = 0; k < lim; k++) |
| 262 | w += hweight32(bitmap[k]); | 261 | w += hweight_long(bitmap[k]); |
| 263 | 262 | ||
| 264 | if (bits % BITS_PER_LONG) | 263 | if (bits % BITS_PER_LONG) |
| 265 | w += hweight32(bitmap[k] & BITMAP_LAST_WORD_MASK(bits)); | 264 | w += hweight_long(bitmap[k] & BITMAP_LAST_WORD_MASK(bits)); |
| 266 | 265 | ||
| 267 | return w; | 266 | return w; |
| 268 | } | 267 | } |
| 269 | #else | ||
| 270 | int __bitmap_weight(const unsigned long *bitmap, int bits) | ||
| 271 | { | ||
| 272 | int k, w = 0, lim = bits/BITS_PER_LONG; | ||
| 273 | |||
| 274 | for (k = 0; k < lim; k++) | ||
| 275 | w += hweight64(bitmap[k]); | ||
| 276 | |||
| 277 | if (bits % BITS_PER_LONG) | ||
| 278 | w += hweight64(bitmap[k] & BITMAP_LAST_WORD_MASK(bits)); | ||
| 279 | |||
| 280 | return w; | ||
| 281 | } | ||
| 282 | #endif | ||
| 283 | EXPORT_SYMBOL(__bitmap_weight); | 268 | EXPORT_SYMBOL(__bitmap_weight); |
| 284 | 269 | ||
| 285 | /* | 270 | /* |
| @@ -676,84 +661,143 @@ int bitmap_bitremap(int oldbit, const unsigned long *old, | |||
| 676 | } | 661 | } |
| 677 | EXPORT_SYMBOL(bitmap_bitremap); | 662 | EXPORT_SYMBOL(bitmap_bitremap); |
| 678 | 663 | ||
| 679 | /** | 664 | /* |
| 680 | * bitmap_find_free_region - find a contiguous aligned mem region | 665 | * Common code for bitmap_*_region() routines. |
| 681 | * @bitmap: an array of unsigned longs corresponding to the bitmap | 666 | * bitmap: array of unsigned longs corresponding to the bitmap |
| 682 | * @bits: number of bits in the bitmap | 667 | * pos: the beginning of the region |
| 683 | * @order: region size to find (size is actually 1<<order) | 668 | * order: region size (log base 2 of number of bits) |
| 669 | * reg_op: operation(s) to perform on that region of bitmap | ||
| 684 | * | 670 | * |
| 685 | * This is used to allocate a memory region from a bitmap. The idea is | 671 | * Can set, verify and/or release a region of bits in a bitmap, |
| 686 | * that the region has to be 1<<order sized and 1<<order aligned (this | 672 | * depending on which combination of REG_OP_* flag bits is set. |
| 687 | * makes the search algorithm much faster). | ||
| 688 | * | 673 | * |
| 689 | * The region is marked as set bits in the bitmap if a free one is | 674 | * A region of a bitmap is a sequence of bits in the bitmap, of |
| 690 | * found. | 675 | * some size '1 << order' (a power of two), aligned to that same |
| 676 | * '1 << order' power of two. | ||
| 691 | * | 677 | * |
| 692 | * Returns either beginning of region or negative error | 678 | * Returns 1 if REG_OP_ISFREE succeeds (region is all zero bits). |
| 679 | * Returns 0 in all other cases and reg_ops. | ||
| 693 | */ | 680 | */ |
| 694 | int bitmap_find_free_region(unsigned long *bitmap, int bits, int order) | ||
| 695 | { | ||
| 696 | unsigned long mask; | ||
| 697 | int pages = 1 << order; | ||
| 698 | int i; | ||
| 699 | 681 | ||
| 700 | if(pages > BITS_PER_LONG) | 682 | enum { |
| 701 | return -EINVAL; | 683 | REG_OP_ISFREE, /* true if region is all zero bits */ |
| 684 | REG_OP_ALLOC, /* set all bits in region */ | ||
| 685 | REG_OP_RELEASE, /* clear all bits in region */ | ||
| 686 | }; | ||
| 702 | 687 | ||
| 703 | /* make a mask of the order */ | 688 | static int __reg_op(unsigned long *bitmap, int pos, int order, int reg_op) |
| 704 | mask = (1ul << (pages - 1)); | 689 | { |
| 690 | int nbits_reg; /* number of bits in region */ | ||
| 691 | int index; /* index first long of region in bitmap */ | ||
| 692 | int offset; /* bit offset region in bitmap[index] */ | ||
| 693 | int nlongs_reg; /* num longs spanned by region in bitmap */ | ||
| 694 | int nbitsinlong; /* num bits of region in each spanned long */ | ||
| 695 | unsigned long mask; /* bitmask for one long of region */ | ||
| 696 | int i; /* scans bitmap by longs */ | ||
| 697 | int ret = 0; /* return value */ | ||
| 698 | |||
| 699 | /* | ||
| 700 | * Either nlongs_reg == 1 (for small orders that fit in one long) | ||
| 701 | * or (offset == 0 && mask == ~0UL) (for larger multiword orders.) | ||
| 702 | */ | ||
| 703 | nbits_reg = 1 << order; | ||
| 704 | index = pos / BITS_PER_LONG; | ||
| 705 | offset = pos - (index * BITS_PER_LONG); | ||
| 706 | nlongs_reg = BITS_TO_LONGS(nbits_reg); | ||
| 707 | nbitsinlong = min(nbits_reg, BITS_PER_LONG); | ||
| 708 | |||
| 709 | /* | ||
| 710 | * Can't do "mask = (1UL << nbitsinlong) - 1", as that | ||
| 711 | * overflows if nbitsinlong == BITS_PER_LONG. | ||
| 712 | */ | ||
| 713 | mask = (1UL << (nbitsinlong - 1)); | ||
| 705 | mask += mask - 1; | 714 | mask += mask - 1; |
| 715 | mask <<= offset; | ||
| 706 | 716 | ||
| 707 | /* run up the bitmap pages bits at a time */ | 717 | switch (reg_op) { |
| 708 | for (i = 0; i < bits; i += pages) { | 718 | case REG_OP_ISFREE: |
| 709 | int index = i/BITS_PER_LONG; | 719 | for (i = 0; i < nlongs_reg; i++) { |
| 710 | int offset = i - (index * BITS_PER_LONG); | 720 | if (bitmap[index + i] & mask) |
| 711 | if((bitmap[index] & (mask << offset)) == 0) { | 721 | goto done; |
| 712 | /* set region in bimap */ | ||
| 713 | bitmap[index] |= (mask << offset); | ||
| 714 | return i; | ||
| 715 | } | 722 | } |
| 723 | ret = 1; /* all bits in region free (zero) */ | ||
| 724 | break; | ||
| 725 | |||
| 726 | case REG_OP_ALLOC: | ||
| 727 | for (i = 0; i < nlongs_reg; i++) | ||
| 728 | bitmap[index + i] |= mask; | ||
| 729 | break; | ||
| 730 | |||
| 731 | case REG_OP_RELEASE: | ||
| 732 | for (i = 0; i < nlongs_reg; i++) | ||
| 733 | bitmap[index + i] &= ~mask; | ||
| 734 | break; | ||
| 716 | } | 735 | } |
| 717 | return -ENOMEM; | 736 | done: |
| 737 | return ret; | ||
| 738 | } | ||
| 739 | |||
| 740 | /** | ||
| 741 | * bitmap_find_free_region - find a contiguous aligned mem region | ||
| 742 | * @bitmap: array of unsigned longs corresponding to the bitmap | ||
| 743 | * @bits: number of bits in the bitmap | ||
| 744 | * @order: region size (log base 2 of number of bits) to find | ||
| 745 | * | ||
| 746 | * Find a region of free (zero) bits in a @bitmap of @bits bits and | ||
| 747 | * allocate them (set them to one). Only consider regions of length | ||
| 748 | * a power (@order) of two, aligned to that power of two, which | ||
| 749 | * makes the search algorithm much faster. | ||
| 750 | * | ||
| 751 | * Return the bit offset in bitmap of the allocated region, | ||
| 752 | * or -errno on failure. | ||
| 753 | */ | ||
| 754 | int bitmap_find_free_region(unsigned long *bitmap, int bits, int order) | ||
| 755 | { | ||
| 756 | int pos; /* scans bitmap by regions of size order */ | ||
| 757 | |||
| 758 | for (pos = 0; pos < bits; pos += (1 << order)) | ||
| 759 | if (__reg_op(bitmap, pos, order, REG_OP_ISFREE)) | ||
| 760 | break; | ||
| 761 | if (pos == bits) | ||
| 762 | return -ENOMEM; | ||
| 763 | __reg_op(bitmap, pos, order, REG_OP_ALLOC); | ||
| 764 | return pos; | ||
| 718 | } | 765 | } |
| 719 | EXPORT_SYMBOL(bitmap_find_free_region); | 766 | EXPORT_SYMBOL(bitmap_find_free_region); |
| 720 | 767 | ||
| 721 | /** | 768 | /** |
| 722 | * bitmap_release_region - release allocated bitmap region | 769 | * bitmap_release_region - release allocated bitmap region |
| 723 | * @bitmap: a pointer to the bitmap | 770 | * @bitmap: array of unsigned longs corresponding to the bitmap |
| 724 | * @pos: the beginning of the region | 771 | * @pos: beginning of bit region to release |
| 725 | * @order: the order of the bits to release (number is 1<<order) | 772 | * @order: region size (log base 2 of number of bits) to release |
| 726 | * | 773 | * |
| 727 | * This is the complement to __bitmap_find_free_region and releases | 774 | * This is the complement to __bitmap_find_free_region and releases |
| 728 | * the found region (by clearing it in the bitmap). | 775 | * the found region (by clearing it in the bitmap). |
| 776 | * | ||
| 777 | * No return value. | ||
| 729 | */ | 778 | */ |
| 730 | void bitmap_release_region(unsigned long *bitmap, int pos, int order) | 779 | void bitmap_release_region(unsigned long *bitmap, int pos, int order) |
| 731 | { | 780 | { |
| 732 | int pages = 1 << order; | 781 | __reg_op(bitmap, pos, order, REG_OP_RELEASE); |
| 733 | unsigned long mask = (1ul << (pages - 1)); | ||
| 734 | int index = pos/BITS_PER_LONG; | ||
| 735 | int offset = pos - (index * BITS_PER_LONG); | ||
| 736 | mask += mask - 1; | ||
| 737 | bitmap[index] &= ~(mask << offset); | ||
| 738 | } | 782 | } |
| 739 | EXPORT_SYMBOL(bitmap_release_region); | 783 | EXPORT_SYMBOL(bitmap_release_region); |
| 740 | 784 | ||
| 785 | /** | ||
| 786 | * bitmap_allocate_region - allocate bitmap region | ||
| 787 | * @bitmap: array of unsigned longs corresponding to the bitmap | ||
| 788 | * @pos: beginning of bit region to allocate | ||
| 789 | * @order: region size (log base 2 of number of bits) to allocate | ||
| 790 | * | ||
| 791 | * Allocate (set bits in) a specified region of a bitmap. | ||
| 792 | * | ||
| 793 | * Return 0 on success, or -EBUSY if specified region wasn't | ||
| 794 | * free (not all bits were zero). | ||
| 795 | */ | ||
| 741 | int bitmap_allocate_region(unsigned long *bitmap, int pos, int order) | 796 | int bitmap_allocate_region(unsigned long *bitmap, int pos, int order) |
| 742 | { | 797 | { |
| 743 | int pages = 1 << order; | 798 | if (!__reg_op(bitmap, pos, order, REG_OP_ISFREE)) |
| 744 | unsigned long mask = (1ul << (pages - 1)); | ||
| 745 | int index = pos/BITS_PER_LONG; | ||
| 746 | int offset = pos - (index * BITS_PER_LONG); | ||
| 747 | |||
| 748 | /* We don't do regions of pages > BITS_PER_LONG. The | ||
| 749 | * algorithm would be a simple look for multiple zeros in the | ||
| 750 | * array, but there's no driver today that needs this. If you | ||
| 751 | * trip this BUG(), you get to code it... */ | ||
| 752 | BUG_ON(pages > BITS_PER_LONG); | ||
| 753 | mask += mask - 1; | ||
| 754 | if (bitmap[index] & (mask << offset)) | ||
| 755 | return -EBUSY; | 799 | return -EBUSY; |
| 756 | bitmap[index] |= (mask << offset); | 800 | __reg_op(bitmap, pos, order, REG_OP_ALLOC); |
| 757 | return 0; | 801 | return 0; |
| 758 | } | 802 | } |
| 759 | EXPORT_SYMBOL(bitmap_allocate_region); | 803 | EXPORT_SYMBOL(bitmap_allocate_region); |
