Blame view

kernel/range.c 3.04 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
27811d8ca   Yinghai Lu   x86: Move range r...
2
3
4
  /*
   * Range add and subtract
   */
27811d8ca   Yinghai Lu   x86: Move range r...
5
  #include <linux/init.h>
b296a6d53   Andy Shevchenko   kernel.h: split o...
6
7
  #include <linux/minmax.h>
  #include <linux/printk.h>
27811d8ca   Yinghai Lu   x86: Move range r...
8
  #include <linux/sort.h>
054188150   Yinghai Lu   range: Do not add...
9
  #include <linux/string.h>
27811d8ca   Yinghai Lu   x86: Move range r...
10
  #include <linux/range.h>
27811d8ca   Yinghai Lu   x86: Move range r...
11
12
  int add_range(struct range *range, int az, int nr_range, u64 start, u64 end)
  {
e9a0064ad   Yinghai Lu   x86: Change range...
13
  	if (start >= end)
27811d8ca   Yinghai Lu   x86: Move range r...
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  		return nr_range;
  
  	/* Out of slots: */
  	if (nr_range >= az)
  		return nr_range;
  
  	range[nr_range].start = start;
  	range[nr_range].end = end;
  
  	nr_range++;
  
  	return nr_range;
  }
  
  int add_range_with_merge(struct range *range, int az, int nr_range,
  		     u64 start, u64 end)
  {
  	int i;
e9a0064ad   Yinghai Lu   x86: Change range...
32
  	if (start >= end)
27811d8ca   Yinghai Lu   x86: Move range r...
33
  		return nr_range;
054188150   Yinghai Lu   range: Do not add...
34
  	/* get new start/end: */
27811d8ca   Yinghai Lu   x86: Move range r...
35
  	for (i = 0; i < nr_range; i++) {
27811d8ca   Yinghai Lu   x86: Move range r...
36
37
38
39
40
41
42
  		u64 common_start, common_end;
  
  		if (!range[i].end)
  			continue;
  
  		common_start = max(range[i].start, start);
  		common_end = min(range[i].end, end);
e9a0064ad   Yinghai Lu   x86: Change range...
43
  		if (common_start > common_end)
27811d8ca   Yinghai Lu   x86: Move range r...
44
  			continue;
054188150   Yinghai Lu   range: Do not add...
45
46
47
  		/* new start/end, will add it back at last */
  		start = min(range[i].start, start);
  		end = max(range[i].end, end);
27811d8ca   Yinghai Lu   x86: Move range r...
48

054188150   Yinghai Lu   range: Do not add...
49
50
51
52
53
54
  		memmove(&range[i], &range[i + 1],
  			(nr_range - (i + 1)) * sizeof(range[i]));
  		range[nr_range - 1].start = 0;
  		range[nr_range - 1].end   = 0;
  		nr_range--;
  		i--;
27811d8ca   Yinghai Lu   x86: Move range r...
55
56
57
58
59
60
61
62
63
  	}
  
  	/* Need to add it: */
  	return add_range(range, az, nr_range, start, end);
  }
  
  void subtract_range(struct range *range, int az, u64 start, u64 end)
  {
  	int i, j;
e9a0064ad   Yinghai Lu   x86: Change range...
64
  	if (start >= end)
27811d8ca   Yinghai Lu   x86: Move range r...
65
66
67
68
69
70
71
72
73
74
75
76
77
  		return;
  
  	for (j = 0; j < az; j++) {
  		if (!range[j].end)
  			continue;
  
  		if (start <= range[j].start && end >= range[j].end) {
  			range[j].start = 0;
  			range[j].end = 0;
  			continue;
  		}
  
  		if (start <= range[j].start && end < range[j].end &&
e9a0064ad   Yinghai Lu   x86: Change range...
78
79
  		    range[j].start < end) {
  			range[j].start = end;
27811d8ca   Yinghai Lu   x86: Move range r...
80
81
82
83
84
  			continue;
  		}
  
  
  		if (start > range[j].start && end >= range[j].end &&
e9a0064ad   Yinghai Lu   x86: Change range...
85
86
  		    range[j].end > start) {
  			range[j].end = start;
27811d8ca   Yinghai Lu   x86: Move range r...
87
88
89
90
91
92
93
94
95
96
97
  			continue;
  		}
  
  		if (start > range[j].start && end < range[j].end) {
  			/* Find the new spare: */
  			for (i = 0; i < az; i++) {
  				if (range[i].end == 0)
  					break;
  			}
  			if (i < az) {
  				range[i].end = range[j].end;
e9a0064ad   Yinghai Lu   x86: Change range...
98
  				range[i].start = end;
27811d8ca   Yinghai Lu   x86: Move range r...
99
  			} else {
7fba2c27a   Lin Feng   kernel/range.c: s...
100
101
102
  				pr_err("%s: run out of slot in ranges
  ",
  					__func__);
27811d8ca   Yinghai Lu   x86: Move range r...
103
  			}
e9a0064ad   Yinghai Lu   x86: Change range...
104
  			range[j].end = start;
27811d8ca   Yinghai Lu   x86: Move range r...
105
106
107
108
109
110
111
112
113
  			continue;
  		}
  	}
  }
  
  static int cmp_range(const void *x1, const void *x2)
  {
  	const struct range *r1 = x1;
  	const struct range *r2 = x2;
27811d8ca   Yinghai Lu   x86: Move range r...
114

fc7f0dd38   Louis Langholtz   kernel: avoid ove...
115
116
117
118
119
  	if (r1->start < r2->start)
  		return -1;
  	if (r1->start > r2->start)
  		return 1;
  	return 0;
27811d8ca   Yinghai Lu   x86: Move range r...
120
121
122
123
  }
  
  int clean_sort_range(struct range *range, int az)
  {
834b40380   Alexey Khoroshilov   kernel/range.c: f...
124
  	int i, j, k = az - 1, nr_range = az;
27811d8ca   Yinghai Lu   x86: Move range r...
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  
  	for (i = 0; i < k; i++) {
  		if (range[i].end)
  			continue;
  		for (j = k; j > i; j--) {
  			if (range[j].end) {
  				k = j;
  				break;
  			}
  		}
  		if (j == i)
  			break;
  		range[i].start = range[k].start;
  		range[i].end   = range[k].end;
  		range[k].start = 0;
  		range[k].end   = 0;
  		k--;
  	}
  	/* count it */
  	for (i = 0; i < az; i++) {
  		if (!range[i].end) {
  			nr_range = i;
  			break;
  		}
  	}
  
  	/* sort them */
  	sort(range, nr_range, sizeof(struct range), cmp_range, NULL);
  
  	return nr_range;
  }
  
  void sort_range(struct range *range, int nr_range)
  {
  	/* sort them */
  	sort(range, nr_range, sizeof(struct range), cmp_range, NULL);
  }