diff options
Diffstat (limited to 'mm/percpu.c')
-rw-r--r-- | mm/percpu.c | 36 |
1 files changed, 27 insertions, 9 deletions
diff --git a/mm/percpu.c b/mm/percpu.c index daebf7a5343c..30e683f42861 100644 --- a/mm/percpu.c +++ b/mm/percpu.c | |||
@@ -707,20 +707,31 @@ static void pcpu_block_update_scan(struct pcpu_chunk *chunk, int bit_off, | |||
707 | /** | 707 | /** |
708 | * pcpu_chunk_refresh_hint - updates metadata about a chunk | 708 | * pcpu_chunk_refresh_hint - updates metadata about a chunk |
709 | * @chunk: chunk of interest | 709 | * @chunk: chunk of interest |
710 | * @full_scan: if we should scan from the beginning | ||
710 | * | 711 | * |
711 | * Iterates over the metadata blocks to find the largest contig area. | 712 | * Iterates over the metadata blocks to find the largest contig area. |
712 | * It also counts the populated pages and uses the delta to update the | 713 | * A full scan can be avoided on the allocation path as this is triggered |
713 | * global count. | 714 | * if we broke the contig_hint. In doing so, the scan_hint will be before |
715 | * the contig_hint or after if the scan_hint == contig_hint. This cannot | ||
716 | * be prevented on freeing as we want to find the largest area possibly | ||
717 | * spanning blocks. | ||
714 | */ | 718 | */ |
715 | static void pcpu_chunk_refresh_hint(struct pcpu_chunk *chunk) | 719 | static void pcpu_chunk_refresh_hint(struct pcpu_chunk *chunk, bool full_scan) |
716 | { | 720 | { |
717 | struct pcpu_block_md *chunk_md = &chunk->chunk_md; | 721 | struct pcpu_block_md *chunk_md = &chunk->chunk_md; |
718 | int bit_off, bits; | 722 | int bit_off, bits; |
719 | 723 | ||
720 | /* clear metadata */ | 724 | /* promote scan_hint to contig_hint */ |
721 | chunk_md->contig_hint = 0; | 725 | if (!full_scan && chunk_md->scan_hint) { |
726 | bit_off = chunk_md->scan_hint_start + chunk_md->scan_hint; | ||
727 | chunk_md->contig_hint_start = chunk_md->scan_hint_start; | ||
728 | chunk_md->contig_hint = chunk_md->scan_hint; | ||
729 | chunk_md->scan_hint = 0; | ||
730 | } else { | ||
731 | bit_off = chunk_md->first_free; | ||
732 | chunk_md->contig_hint = 0; | ||
733 | } | ||
722 | 734 | ||
723 | bit_off = chunk_md->first_free; | ||
724 | bits = 0; | 735 | bits = 0; |
725 | pcpu_for_each_md_free_region(chunk, bit_off, bits) { | 736 | pcpu_for_each_md_free_region(chunk, bit_off, bits) { |
726 | pcpu_block_update(chunk_md, bit_off, bit_off + bits); | 737 | pcpu_block_update(chunk_md, bit_off, bit_off + bits); |
@@ -880,6 +891,13 @@ static void pcpu_block_update_hint_alloc(struct pcpu_chunk *chunk, int bit_off, | |||
880 | if (nr_empty_pages) | 891 | if (nr_empty_pages) |
881 | pcpu_update_empty_pages(chunk, -nr_empty_pages); | 892 | pcpu_update_empty_pages(chunk, -nr_empty_pages); |
882 | 893 | ||
894 | if (pcpu_region_overlap(chunk_md->scan_hint_start, | ||
895 | chunk_md->scan_hint_start + | ||
896 | chunk_md->scan_hint, | ||
897 | bit_off, | ||
898 | bit_off + bits)) | ||
899 | chunk_md->scan_hint = 0; | ||
900 | |||
883 | /* | 901 | /* |
884 | * The only time a full chunk scan is required is if the chunk | 902 | * The only time a full chunk scan is required is if the chunk |
885 | * contig hint is broken. Otherwise, it means a smaller space | 903 | * contig hint is broken. Otherwise, it means a smaller space |
@@ -890,7 +908,7 @@ static void pcpu_block_update_hint_alloc(struct pcpu_chunk *chunk, int bit_off, | |||
890 | chunk_md->contig_hint, | 908 | chunk_md->contig_hint, |
891 | bit_off, | 909 | bit_off, |
892 | bit_off + bits)) | 910 | bit_off + bits)) |
893 | pcpu_chunk_refresh_hint(chunk); | 911 | pcpu_chunk_refresh_hint(chunk, false); |
894 | } | 912 | } |
895 | 913 | ||
896 | /** | 914 | /** |
@@ -1001,7 +1019,7 @@ static void pcpu_block_update_hint_free(struct pcpu_chunk *chunk, int bit_off, | |||
1001 | * the else condition below. | 1019 | * the else condition below. |
1002 | */ | 1020 | */ |
1003 | if (((end - start) >= PCPU_BITMAP_BLOCK_BITS) || s_index != e_index) | 1021 | if (((end - start) >= PCPU_BITMAP_BLOCK_BITS) || s_index != e_index) |
1004 | pcpu_chunk_refresh_hint(chunk); | 1022 | pcpu_chunk_refresh_hint(chunk, true); |
1005 | else | 1023 | else |
1006 | pcpu_block_update(&chunk->chunk_md, | 1024 | pcpu_block_update(&chunk->chunk_md, |
1007 | pcpu_block_off_to_off(s_index, start), | 1025 | pcpu_block_off_to_off(s_index, start), |
@@ -1074,7 +1092,7 @@ static int pcpu_find_block_fit(struct pcpu_chunk *chunk, int alloc_bits, | |||
1074 | if (bit_off + alloc_bits > chunk_md->contig_hint) | 1092 | if (bit_off + alloc_bits > chunk_md->contig_hint) |
1075 | return -1; | 1093 | return -1; |
1076 | 1094 | ||
1077 | bit_off = chunk_md->first_free; | 1095 | bit_off = pcpu_next_hint(chunk_md, alloc_bits); |
1078 | bits = 0; | 1096 | bits = 0; |
1079 | pcpu_for_each_fit_region(chunk, alloc_bits, align, bit_off, bits) { | 1097 | pcpu_for_each_fit_region(chunk, alloc_bits, align, bit_off, bits) { |
1080 | if (!pop_only || pcpu_is_populated(chunk, bit_off, bits, | 1098 | if (!pop_only || pcpu_is_populated(chunk, bit_off, bits, |