Commit 74373c6acc52450ced28780d5fece60f1d7d20aa

Authored by Paul Mundt
Committed by Linus Torvalds
1 parent 87e2480258

[PATCH] bitmap: region multiword spanning support

Add support to the lib/bitmap.c bitmap_*_region() routines

For bitmap regions larger than one word (nbits > BITS_PER_LONG).  This removes
a BUG_ON() in lib bitmap.

I have an updated store queue API for SH that is currently using this with
relative success, and at first glance, it seems like this could be useful for
x86 (arch/i386/kernel/pci-dma.c) as well.  Particularly for anything using
dma_declare_coherent_memory() on large areas and that attempts to allocate
large buffers from that space.

Paul Jackson also did some cleanup to this patch.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Signed-off-by: Paul Jackson <pj@sgi.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

Showing 1 changed file with 76 additions and 34 deletions Side-by-side Diff

... ... @@ -692,26 +692,44 @@
692 692 */
693 693 int bitmap_find_free_region(unsigned long *bitmap, int bits, int order)
694 694 {
695   - unsigned long mask;
696   - int nbits = 1 << order;
697   - int i;
  695 + int nbits; /* number of bits in region */
  696 + int nlongs; /* num longs spanned by region in bitmap */
  697 + int nbitsinlong; /* num bits of region in each spanned long */
  698 + unsigned long mask; /* bitmask of bits [0 .. nbitsinlong-1] */
  699 + int i; /* scans bitmap by longs */
698 700  
699   - if (nbits > BITS_PER_LONG)
700   - return -EINVAL;
  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 707 /* make a mask of the order */
703   - mask = (1UL << (nbits - 1));
  708 + mask = (1UL << (nbitsinlong - 1));
704 709 mask += mask - 1;
705 710  
706   - /* run up the bitmap nbits at a time */
707   - for (i = 0; i < bits; i += nbits) {
  711 + /* run up the bitmap nbitsinlong at a time */
  712 + for (i = 0; i < bits; i += nbitsinlong) {
708 713 int index = i / BITS_PER_LONG;
709 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 729 /* set region in bitmap */
712   - bitmap[index] |= (mask << offset);
713   - return i;
714   - }
  730 + bitmap[index + j] |= (mask << offset);
  731 +
  732 + return i;
715 733 }
716 734 return -ENOMEM;
717 735 }
718 736  
719 737  
... ... @@ -728,13 +746,28 @@
728 746 */
729 747 void bitmap_release_region(unsigned long *bitmap, int pos, int order)
730 748 {
731   - int nbits = 1 << order;
732   - unsigned long mask = (1UL << (nbits - 1));
733   - int index = pos / BITS_PER_LONG;
734   - int offset = pos - (index * BITS_PER_LONG);
  749 + int nbits; /* number of bits in region */
  750 + int nlongs; /* num longs spanned by region in bitmap */
  751 + int index; /* index first long of region in bitmap */
  752 + int offset; /* bit offset region in bitmap[index] */
  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 */
735 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 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 }
739 772 EXPORT_SYMBOL(bitmap_release_region);
740 773  
741 774  
742 775  
... ... @@ -750,22 +783,31 @@
750 783 */
751 784 int bitmap_allocate_region(unsigned long *bitmap, int pos, int order)
752 785 {
753   - int nbits = 1 << order;
754   - unsigned long mask = (1UL << (nbits - 1));
755   - int index = pos / BITS_PER_LONG;
756   - int offset = pos - (index * BITS_PER_LONG);
  786 + int nbits; /* number of bits in region */
  787 + int nlongs; /* num longs spanned by region in bitmap */
  788 + int index; /* index first long of region in bitmap */
  789 + int offset; /* bit offset region in bitmap[index] */
  790 + int nbitsinlong; /* num bits of region in each spanned long */
  791 + unsigned long mask; /* bitmask of bits [0 .. nbitsinlong-1] */
  792 + int i; /* scans bitmap by longs */
757 793  
758   - /*
759   - * We don't do regions of nbits > BITS_PER_LONG. The
760   - * algorithm would be a simple look for multiple zeros in the
761   - * array, but there's no driver today that needs this. If you
762   - * trip this BUG(), you get to code it...
763   - */
764   - BUG_ON(nbits > BITS_PER_LONG);
  794 + nbits = 1 << order;
  795 + nlongs = (nbits + (BITS_PER_LONG - 1)) / BITS_PER_LONG;
  796 + index = pos / 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 804 mask += mask - 1;
766   - if (bitmap[index] & (mask << offset))
767   - return -EBUSY;
768   - bitmap[index] |= (mask << offset);
  805 +
  806 + for (i = 0; i < nlongs; i++)
  807 + if (bitmap[index + i] & (mask << offset))
  808 + return -EBUSY;
  809 + for (i = 0; i < nlongs; i++)
  810 + bitmap[index + i] |= (mask << offset);
769 811 return 0;
770 812 }
771 813 EXPORT_SYMBOL(bitmap_allocate_region);