1 /* 2 * Range add and subtract 3 */ 4 #include <linux/kernel.h> 5 #include <linux/init.h> 6 #include <linux/sort.h> 7 8 #include <linux/range.h> 9 10 int add_range(struct range *range, int az, int nr_range, u64 start, u64 end) 11 { 12 if (start >= end) 13 return nr_range; 14 15 /* Out of slots: */ 16 if (nr_range >= az) 17 return nr_range; 18 19 range[nr_range].start = start; 20 range[nr_range].end = end; 21 22 nr_range++; 23 24 return nr_range; 25 } 26 27 int add_range_with_merge(struct range *range, int az, int nr_range, 28 u64 start, u64 end) 29 { 30 int i; 31 32 if (start >= end) 33 return nr_range; 34 35 /* Try to merge it with old one: */ 36 for (i = 0; i < nr_range; i++) { 37 u64 final_start, final_end; 38 u64 common_start, common_end; 39 40 if (!range[i].end) 41 continue; 42 43 common_start = max(range[i].start, start); 44 common_end = min(range[i].end, end); 45 if (common_start > common_end) 46 continue; 47 48 final_start = min(range[i].start, start); 49 final_end = max(range[i].end, end); 50 51 /* clear it and add it back for further merge */ 52 range[i].start = 0; 53 range[i].end = 0; 54 return add_range_with_merge(range, az, nr_range, 55 final_start, final_end); 56 } 57 58 /* Need to add it: */ 59 return add_range(range, az, nr_range, start, end); 60 } 61 62 void subtract_range(struct range *range, int az, u64 start, u64 end) 63 { 64 int i, j; 65 66 if (start >= end) 67 return; 68 69 for (j = 0; j < az; j++) { 70 if (!range[j].end) 71 continue; 72 73 if (start <= range[j].start && end >= range[j].end) { 74 range[j].start = 0; 75 range[j].end = 0; 76 continue; 77 } 78 79 if (start <= range[j].start && end < range[j].end && 80 range[j].start < end) { 81 range[j].start = end; 82 continue; 83 } 84 85 86 if (start > range[j].start && end >= range[j].end && 87 range[j].end > start) { 88 range[j].end = start; 89 continue; 90 } 91 92 if (start > range[j].start && end < range[j].end) { 93 /* Find the new spare: */ 94 for (i = 0; i < az; i++) { 95 if (range[i].end == 0) 96 break; 97 } 98 if (i < az) { 99 range[i].end = range[j].end; 100 range[i].start = end; 101 } else { 102 pr_err("%s: run out of slot in ranges\n", 103 __func__); 104 } 105 range[j].end = start; 106 continue; 107 } 108 } 109 } 110 111 static int cmp_range(const void *x1, const void *x2) 112 { 113 const struct range *r1 = x1; 114 const struct range *r2 = x2; 115 s64 start1, start2; 116 117 start1 = r1->start; 118 start2 = r2->start; 119 120 return start1 - start2; 121 } 122 123 int clean_sort_range(struct range *range, int az) 124 { 125 int i, j, k = az - 1, nr_range = az; 126 127 for (i = 0; i < k; i++) { 128 if (range[i].end) 129 continue; 130 for (j = k; j > i; j--) { 131 if (range[j].end) { 132 k = j; 133 break; 134 } 135 } 136 if (j == i) 137 break; 138 range[i].start = range[k].start; 139 range[i].end = range[k].end; 140 range[k].start = 0; 141 range[k].end = 0; 142 k--; 143 } 144 /* count it */ 145 for (i = 0; i < az; i++) { 146 if (!range[i].end) { 147 nr_range = i; 148 break; 149 } 150 } 151 152 /* sort them */ 153 sort(range, nr_range, sizeof(struct range), cmp_range, NULL); 154 155 return nr_range; 156 } 157 158 void sort_range(struct range *range, int nr_range) 159 { 160 /* sort them */ 161 sort(range, nr_range, sizeof(struct range), cmp_range, NULL); 162 } 163