aboutsummaryrefslogtreecommitdiffstats
path: root/lib/bitmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/bitmap.c')
-rw-r--r--lib/bitmap.c163
1 files changed, 111 insertions, 52 deletions
diff --git a/lib/bitmap.c b/lib/bitmap.c
index 48e708381d44..8acab0e176ef 100644
--- a/lib/bitmap.c
+++ b/lib/bitmap.c
@@ -676,84 +676,143 @@ int bitmap_bitremap(int oldbit, const unsigned long *old,
676} 676}
677EXPORT_SYMBOL(bitmap_bitremap); 677EXPORT_SYMBOL(bitmap_bitremap);
678 678
679/** 679/*
680 * bitmap_find_free_region - find a contiguous aligned mem region 680 * Common code for bitmap_*_region() routines.
681 * @bitmap: an array of unsigned longs corresponding to the bitmap 681 * bitmap: array of unsigned longs corresponding to the bitmap
682 * @bits: number of bits in the bitmap 682 * pos: the beginning of the region
683 * @order: region size to find (size is actually 1<<order) 683 * order: region size (log base 2 of number of bits)
684 * reg_op: operation(s) to perform on that region of bitmap
684 * 685 *
685 * This is used to allocate a memory region from a bitmap. The idea is 686 * 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 687 * depending on which combination of REG_OP_* flag bits is set.
687 * makes the search algorithm much faster).
688 * 688 *
689 * The region is marked as set bits in the bitmap if a free one is 689 * A region of a bitmap is a sequence of bits in the bitmap, of
690 * found. 690 * some size '1 << order' (a power of two), aligned to that same
691 * '1 << order' power of two.
691 * 692 *
692 * Returns either beginning of region or negative error 693 * Returns 1 if REG_OP_ISFREE succeeds (region is all zero bits).
694 * Returns 0 in all other cases and reg_ops.
693 */ 695 */
694int 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 696
700 if(pages > BITS_PER_LONG) 697enum {
701 return -EINVAL; 698 REG_OP_ISFREE, /* true if region is all zero bits */
699 REG_OP_ALLOC, /* set all bits in region */
700 REG_OP_RELEASE, /* clear all bits in region */
701};
702 702
703 /* make a mask of the order */ 703static int __reg_op(unsigned long *bitmap, int pos, int order, int reg_op)
704 mask = (1ul << (pages - 1)); 704{
705 int nbits_reg; /* number of bits in region */
706 int index; /* index first long of region in bitmap */
707 int offset; /* bit offset region in bitmap[index] */
708 int nlongs_reg; /* num longs spanned by region in bitmap */
709 int nbitsinlong; /* num bits of region in each spanned long */
710 unsigned long mask; /* bitmask for one long of region */
711 int i; /* scans bitmap by longs */
712 int ret = 0; /* return value */
713
714 /*
715 * Either nlongs_reg == 1 (for small orders that fit in one long)
716 * or (offset == 0 && mask == ~0UL) (for larger multiword orders.)
717 */
718 nbits_reg = 1 << order;
719 index = pos / BITS_PER_LONG;
720 offset = pos - (index * BITS_PER_LONG);
721 nlongs_reg = BITS_TO_LONGS(nbits_reg);
722 nbitsinlong = min(nbits_reg, BITS_PER_LONG);
723
724 /*
725 * Can't do "mask = (1UL << nbitsinlong) - 1", as that
726 * overflows if nbitsinlong == BITS_PER_LONG.
727 */
728 mask = (1UL << (nbitsinlong - 1));
705 mask += mask - 1; 729 mask += mask - 1;
730 mask <<= offset;
706 731
707 /* run up the bitmap pages bits at a time */ 732 switch (reg_op) {
708 for (i = 0; i < bits; i += pages) { 733 case REG_OP_ISFREE:
709 int index = i/BITS_PER_LONG; 734 for (i = 0; i < nlongs_reg; i++) {
710 int offset = i - (index * BITS_PER_LONG); 735 if (bitmap[index + i] & mask)
711 if((bitmap[index] & (mask << offset)) == 0) { 736 goto done;
712 /* set region in bimap */
713 bitmap[index] |= (mask << offset);
714 return i;
715 } 737 }
738 ret = 1; /* all bits in region free (zero) */
739 break;
740
741 case REG_OP_ALLOC:
742 for (i = 0; i < nlongs_reg; i++)
743 bitmap[index + i] |= mask;
744 break;
745
746 case REG_OP_RELEASE:
747 for (i = 0; i < nlongs_reg; i++)
748 bitmap[index + i] &= ~mask;
749 break;
716 } 750 }
717 return -ENOMEM; 751done:
752 return ret;
753}
754
755/**
756 * bitmap_find_free_region - find a contiguous aligned mem region
757 * @bitmap: array of unsigned longs corresponding to the bitmap
758 * @bits: number of bits in the bitmap
759 * @order: region size (log base 2 of number of bits) to find
760 *
761 * Find a region of free (zero) bits in a @bitmap of @bits bits and
762 * allocate them (set them to one). Only consider regions of length
763 * a power (@order) of two, aligned to that power of two, which
764 * makes the search algorithm much faster.
765 *
766 * Return the bit offset in bitmap of the allocated region,
767 * or -errno on failure.
768 */
769int bitmap_find_free_region(unsigned long *bitmap, int bits, int order)
770{
771 int pos; /* scans bitmap by regions of size order */
772
773 for (pos = 0; pos < bits; pos += (1 << order))
774 if (__reg_op(bitmap, pos, order, REG_OP_ISFREE))
775 break;
776 if (pos == bits)
777 return -ENOMEM;
778 __reg_op(bitmap, pos, order, REG_OP_ALLOC);
779 return pos;
718} 780}
719EXPORT_SYMBOL(bitmap_find_free_region); 781EXPORT_SYMBOL(bitmap_find_free_region);
720 782
721/** 783/**
722 * bitmap_release_region - release allocated bitmap region 784 * bitmap_release_region - release allocated bitmap region
723 * @bitmap: a pointer to the bitmap 785 * @bitmap: array of unsigned longs corresponding to the bitmap
724 * @pos: the beginning of the region 786 * @pos: beginning of bit region to release
725 * @order: the order of the bits to release (number is 1<<order) 787 * @order: region size (log base 2 of number of bits) to release
726 * 788 *
727 * This is the complement to __bitmap_find_free_region and releases 789 * This is the complement to __bitmap_find_free_region and releases
728 * the found region (by clearing it in the bitmap). 790 * the found region (by clearing it in the bitmap).
791 *
792 * No return value.
729 */ 793 */
730void bitmap_release_region(unsigned long *bitmap, int pos, int order) 794void bitmap_release_region(unsigned long *bitmap, int pos, int order)
731{ 795{
732 int pages = 1 << order; 796 __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} 797}
739EXPORT_SYMBOL(bitmap_release_region); 798EXPORT_SYMBOL(bitmap_release_region);
740 799
800/**
801 * bitmap_allocate_region - allocate bitmap region
802 * @bitmap: array of unsigned longs corresponding to the bitmap
803 * @pos: beginning of bit region to allocate
804 * @order: region size (log base 2 of number of bits) to allocate
805 *
806 * Allocate (set bits in) a specified region of a bitmap.
807 *
808 * Return 0 on success, or -EBUSY if specified region wasn't
809 * free (not all bits were zero).
810 */
741int bitmap_allocate_region(unsigned long *bitmap, int pos, int order) 811int bitmap_allocate_region(unsigned long *bitmap, int pos, int order)
742{ 812{
743 int pages = 1 << order; 813 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; 814 return -EBUSY;
756 bitmap[index] |= (mask << offset); 815 __reg_op(bitmap, pos, order, REG_OP_ALLOC);
757 return 0; 816 return 0;
758} 817}
759EXPORT_SYMBOL(bitmap_allocate_region); 818EXPORT_SYMBOL(bitmap_allocate_region);