aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/bitmap.c110
1 files changed, 76 insertions, 34 deletions
diff --git a/lib/bitmap.c b/lib/bitmap.c
index 3fab1ce9ac65..f49eabe09271 100644
--- a/lib/bitmap.c
+++ b/lib/bitmap.c
@@ -692,26 +692,44 @@ EXPORT_SYMBOL(bitmap_bitremap);
692 */ 692 */
693int bitmap_find_free_region(unsigned long *bitmap, int bits, int order) 693int bitmap_find_free_region(unsigned long *bitmap, int bits, int order)
694{ 694{
695 unsigned long mask; 695 int nbits; /* number of bits in region */
696 int nbits = 1 << order; 696 int nlongs; /* num longs spanned by region in bitmap */
697 int i; 697 int nbitsinlong; /* num bits of region in each spanned long */
698 698 unsigned long mask; /* bitmask of bits [0 .. nbitsinlong-1] */
699 if (nbits > BITS_PER_LONG) 699 int i; /* scans bitmap by longs */
700 return -EINVAL; 700
701 nbits = 1 << order;
702 nlongs = (nbits + (BITS_PER_LONG - 1)) / BITS_PER_LONG;
703 nbitsinlong = nbits;
704 if (nbitsinlong > BITS_PER_LONG)
705 nbitsinlong = BITS_PER_LONG;
701 706
702 /* make a mask of the order */ 707 /* make a mask of the order */
703 mask = (1UL << (nbits - 1)); 708 mask = (1UL << (nbitsinlong - 1));
704 mask += mask - 1; 709 mask += mask - 1;
705 710
706 /* run up the bitmap nbits at a time */ 711 /* run up the bitmap nbitsinlong at a time */
707 for (i = 0; i < bits; i += nbits) { 712 for (i = 0; i < bits; i += nbitsinlong) {
708 int index = i / BITS_PER_LONG; 713 int index = i / BITS_PER_LONG;
709 int offset = i - (index * BITS_PER_LONG); 714 int offset = i - (index * BITS_PER_LONG);
710 if ((bitmap[index] & (mask << offset)) == 0) { 715 int j, space = 1;
716
717 /* find space in the bitmap */
718 for (j = 0; j < nlongs; j++)
719 if ((bitmap[index + j] & (mask << offset))) {
720 space = 0;
721 break;
722 }
723
724 /* keep looking */
725 if (unlikely(!space))
726 continue;
727
728 for (j = 0; j < nlongs; j++)
711 /* set region in bitmap */ 729 /* set region in bitmap */
712 bitmap[index] |= (mask << offset); 730 bitmap[index + j] |= (mask << offset);
713 return i; 731
714 } 732 return i;
715 } 733 }
716 return -ENOMEM; 734 return -ENOMEM;
717} 735}
@@ -728,13 +746,28 @@ EXPORT_SYMBOL(bitmap_find_free_region);
728 */ 746 */
729void bitmap_release_region(unsigned long *bitmap, int pos, int order) 747void bitmap_release_region(unsigned long *bitmap, int pos, int order)
730{ 748{
731 int nbits = 1 << order; 749 int nbits; /* number of bits in region */
732 unsigned long mask = (1UL << (nbits - 1)); 750 int nlongs; /* num longs spanned by region in bitmap */
733 int index = pos / BITS_PER_LONG; 751 int index; /* index first long of region in bitmap */
734 int offset = pos - (index * BITS_PER_LONG); 752 int offset; /* bit offset region in bitmap[index] */
735 753 int nbitsinlong; /* num bits of region in each spanned long */
754 unsigned long mask; /* bitmask of bits [0 .. nbitsinlong-1] */
755 int i; /* scans bitmap by longs */
756
757 nbits = 1 << order;
758 nlongs = (nbits + (BITS_PER_LONG - 1)) / BITS_PER_LONG;
759 index = pos / BITS_PER_LONG;
760 offset = pos - (index * BITS_PER_LONG);
761
762 nbitsinlong = nbits;
763 if (nbitsinlong > BITS_PER_LONG)
764 nbitsinlong = BITS_PER_LONG;
765
766 mask = (1UL << (nbitsinlong - 1));
736 mask += mask - 1; 767 mask += mask - 1;
737 bitmap[index] &= ~(mask << offset); 768
769 for (i = 0; i < nlongs; i++)
770 bitmap[index + i] &= ~(mask << offset);
738} 771}
739EXPORT_SYMBOL(bitmap_release_region); 772EXPORT_SYMBOL(bitmap_release_region);
740 773
@@ -750,22 +783,31 @@ EXPORT_SYMBOL(bitmap_release_region);
750 */ 783 */
751int bitmap_allocate_region(unsigned long *bitmap, int pos, int order) 784int bitmap_allocate_region(unsigned long *bitmap, int pos, int order)
752{ 785{
753 int nbits = 1 << order; 786 int nbits; /* number of bits in region */
754 unsigned long mask = (1UL << (nbits - 1)); 787 int nlongs; /* num longs spanned by region in bitmap */
755 int index = pos / BITS_PER_LONG; 788 int index; /* index first long of region in bitmap */
756 int offset = pos - (index * BITS_PER_LONG); 789 int offset; /* bit offset region in bitmap[index] */
757 790 int nbitsinlong; /* num bits of region in each spanned long */
758 /* 791 unsigned long mask; /* bitmask of bits [0 .. nbitsinlong-1] */
759 * We don't do regions of nbits > BITS_PER_LONG. The 792 int i; /* scans bitmap by longs */
760 * algorithm would be a simple look for multiple zeros in the 793
761 * array, but there's no driver today that needs this. If you 794 nbits = 1 << order;
762 * trip this BUG(), you get to code it... 795 nlongs = (nbits + (BITS_PER_LONG - 1)) / BITS_PER_LONG;
763 */ 796 index = pos / BITS_PER_LONG;
764 BUG_ON(nbits > BITS_PER_LONG); 797 offset = pos - (index * BITS_PER_LONG);
798
799 nbitsinlong = nbits;
800 if (nbitsinlong > BITS_PER_LONG)
801 nbitsinlong = BITS_PER_LONG;
802
803 mask = (1UL << (nbitsinlong - 1));
765 mask += mask - 1; 804 mask += mask - 1;
766 if (bitmap[index] & (mask << offset)) 805
767 return -EBUSY; 806 for (i = 0; i < nlongs; i++)
768 bitmap[index] |= (mask << offset); 807 if (bitmap[index + i] & (mask << offset))
808 return -EBUSY;
809 for (i = 0; i < nlongs; i++)
810 bitmap[index + i] |= (mask << offset);
769 return 0; 811 return 0;
770} 812}
771EXPORT_SYMBOL(bitmap_allocate_region); 813EXPORT_SYMBOL(bitmap_allocate_region);