Commit 74373c6acc52450ced28780d5fece60f1d7d20aa
Committed by
Linus Torvalds
1 parent
87e2480258
Exists in
master
and in
20 other branches
[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
lib/bitmap.c
... | ... | @@ -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); |