]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - lib/sbitmap.c
sbitmap: push per-cpu last_tag into sbitmap_queue
[mirror_ubuntu-zesty-kernel.git] / lib / sbitmap.c
CommitLineData
88459642
OS
1/*
2 * Copyright (C) 2016 Facebook
3 * Copyright (C) 2013-2014 Jens Axboe
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public
7 * License v2 as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18#include <linux/sbitmap.h>
19
20int sbitmap_init_node(struct sbitmap *sb, unsigned int depth, int shift,
21 gfp_t flags, int node)
22{
23 unsigned int bits_per_word;
24 unsigned int i;
25
26 if (shift < 0) {
27 shift = ilog2(BITS_PER_LONG);
28 /*
29 * If the bitmap is small, shrink the number of bits per word so
30 * we spread over a few cachelines, at least. If less than 4
31 * bits, just forget about it, it's not going to work optimally
32 * anyway.
33 */
34 if (depth >= 4) {
35 while ((4U << shift) > depth)
36 shift--;
37 }
38 }
39 bits_per_word = 1U << shift;
40 if (bits_per_word > BITS_PER_LONG)
41 return -EINVAL;
42
43 sb->shift = shift;
44 sb->depth = depth;
45 sb->map_nr = DIV_ROUND_UP(sb->depth, bits_per_word);
46
47 if (depth == 0) {
48 sb->map = NULL;
49 return 0;
50 }
51
52 sb->map = kzalloc_node(sb->map_nr * sizeof(*sb->map), flags, node);
53 if (!sb->map)
54 return -ENOMEM;
55
56 for (i = 0; i < sb->map_nr; i++) {
57 sb->map[i].depth = min(depth, bits_per_word);
58 depth -= sb->map[i].depth;
59 }
60 return 0;
61}
62EXPORT_SYMBOL_GPL(sbitmap_init_node);
63
64void sbitmap_resize(struct sbitmap *sb, unsigned int depth)
65{
66 unsigned int bits_per_word = 1U << sb->shift;
67 unsigned int i;
68
69 sb->depth = depth;
70 sb->map_nr = DIV_ROUND_UP(sb->depth, bits_per_word);
71
72 for (i = 0; i < sb->map_nr; i++) {
73 sb->map[i].depth = min(depth, bits_per_word);
74 depth -= sb->map[i].depth;
75 }
76}
77EXPORT_SYMBOL_GPL(sbitmap_resize);
78
79static int __sbitmap_get_word(struct sbitmap_word *word, unsigned int hint,
80 bool wrap)
81{
82 unsigned int orig_hint = hint;
83 int nr;
84
85 while (1) {
86 nr = find_next_zero_bit(&word->word, word->depth, hint);
87 if (unlikely(nr >= word->depth)) {
88 /*
89 * We started with an offset, and we didn't reset the
90 * offset to 0 in a failure case, so start from 0 to
91 * exhaust the map.
92 */
93 if (orig_hint && hint && wrap) {
94 hint = orig_hint = 0;
95 continue;
96 }
97 return -1;
98 }
99
100 if (!test_and_set_bit(nr, &word->word))
101 break;
102
103 hint = nr + 1;
104 if (hint >= word->depth - 1)
105 hint = 0;
106 }
107
108 return nr;
109}
110
111int sbitmap_get(struct sbitmap *sb, unsigned int alloc_hint, bool round_robin)
112{
113 unsigned int i, index;
114 int nr = -1;
115
116 index = SB_NR_TO_INDEX(sb, alloc_hint);
117
118 for (i = 0; i < sb->map_nr; i++) {
119 nr = __sbitmap_get_word(&sb->map[index],
120 SB_NR_TO_BIT(sb, alloc_hint),
121 !round_robin);
122 if (nr != -1) {
123 nr += index << sb->shift;
124 break;
125 }
126
127 /* Jump to next index. */
128 index++;
129 alloc_hint = index << sb->shift;
130
131 if (index >= sb->map_nr) {
132 index = 0;
133 alloc_hint = 0;
134 }
135 }
136
137 return nr;
138}
139EXPORT_SYMBOL_GPL(sbitmap_get);
140
141bool sbitmap_any_bit_set(const struct sbitmap *sb)
142{
143 unsigned int i;
144
145 for (i = 0; i < sb->map_nr; i++) {
146 if (sb->map[i].word)
147 return true;
148 }
149 return false;
150}
151EXPORT_SYMBOL_GPL(sbitmap_any_bit_set);
152
153bool sbitmap_any_bit_clear(const struct sbitmap *sb)
154{
155 unsigned int i;
156
157 for (i = 0; i < sb->map_nr; i++) {
158 const struct sbitmap_word *word = &sb->map[i];
159 unsigned long ret;
160
161 ret = find_first_zero_bit(&word->word, word->depth);
162 if (ret < word->depth)
163 return true;
164 }
165 return false;
166}
167EXPORT_SYMBOL_GPL(sbitmap_any_bit_clear);
168
169unsigned int sbitmap_weight(const struct sbitmap *sb)
170{
171 unsigned int i, weight;
172
173 for (i = 0; i < sb->map_nr; i++) {
174 const struct sbitmap_word *word = &sb->map[i];
175
176 weight += bitmap_weight(&word->word, word->depth);
177 }
178 return weight;
179}
180EXPORT_SYMBOL_GPL(sbitmap_weight);
181
182static unsigned int sbq_calc_wake_batch(unsigned int depth)
183{
184 unsigned int wake_batch;
185
186 /*
187 * For each batch, we wake up one queue. We need to make sure that our
188 * batch size is small enough that the full depth of the bitmap is
189 * enough to wake up all of the queues.
190 */
191 wake_batch = SBQ_WAKE_BATCH;
192 if (wake_batch > depth / SBQ_WAIT_QUEUES)
193 wake_batch = max(1U, depth / SBQ_WAIT_QUEUES);
194
195 return wake_batch;
196}
197
198int sbitmap_queue_init_node(struct sbitmap_queue *sbq, unsigned int depth,
199 int shift, gfp_t flags, int node)
200{
201 int ret;
202 int i;
203
204 ret = sbitmap_init_node(&sbq->sb, depth, shift, flags, node);
205 if (ret)
206 return ret;
207
40aabb67
OS
208 sbq->alloc_hint = alloc_percpu_gfp(unsigned int, flags);
209 if (!sbq->alloc_hint) {
210 sbitmap_free(&sbq->sb);
211 return -ENOMEM;
212 }
213
88459642
OS
214 sbq->wake_batch = sbq_calc_wake_batch(depth);
215 atomic_set(&sbq->wake_index, 0);
216
48e28166 217 sbq->ws = kzalloc_node(SBQ_WAIT_QUEUES * sizeof(*sbq->ws), flags, node);
88459642 218 if (!sbq->ws) {
40aabb67 219 free_percpu(sbq->alloc_hint);
88459642
OS
220 sbitmap_free(&sbq->sb);
221 return -ENOMEM;
222 }
223
224 for (i = 0; i < SBQ_WAIT_QUEUES; i++) {
225 init_waitqueue_head(&sbq->ws[i].wait);
226 atomic_set(&sbq->ws[i].wait_cnt, sbq->wake_batch);
227 }
228 return 0;
229}
230EXPORT_SYMBOL_GPL(sbitmap_queue_init_node);
231
232void sbitmap_queue_resize(struct sbitmap_queue *sbq, unsigned int depth)
233{
234 sbq->wake_batch = sbq_calc_wake_batch(depth);
235 sbitmap_resize(&sbq->sb, depth);
236}
237EXPORT_SYMBOL_GPL(sbitmap_queue_resize);
238
40aabb67
OS
239int __sbitmap_queue_get(struct sbitmap_queue *sbq, bool round_robin)
240{
241 unsigned int hint;
242 int nr;
243
244 hint = this_cpu_read(*sbq->alloc_hint);
245 nr = sbitmap_get(&sbq->sb, hint, round_robin);
246
247 if (nr == -1) {
248 /* If the map is full, a hint won't do us much good. */
249 this_cpu_write(*sbq->alloc_hint, 0);
250 } else if (nr == hint || unlikely(round_robin)) {
251 /* Only update the hint if we used it. */
252 hint = nr + 1;
253 if (hint >= sbq->sb.depth - 1)
254 hint = 0;
255 this_cpu_write(*sbq->alloc_hint, hint);
256 }
257
258 return nr;
259}
260EXPORT_SYMBOL_GPL(__sbitmap_queue_get);
261
88459642
OS
262static struct sbq_wait_state *sbq_wake_ptr(struct sbitmap_queue *sbq)
263{
264 int i, wake_index;
265
266 wake_index = atomic_read(&sbq->wake_index);
267 for (i = 0; i < SBQ_WAIT_QUEUES; i++) {
268 struct sbq_wait_state *ws = &sbq->ws[wake_index];
269
270 if (waitqueue_active(&ws->wait)) {
271 int o = atomic_read(&sbq->wake_index);
272
273 if (wake_index != o)
274 atomic_cmpxchg(&sbq->wake_index, o, wake_index);
275 return ws;
276 }
277
278 wake_index = sbq_index_inc(wake_index);
279 }
280
281 return NULL;
282}
283
284static void sbq_wake_up(struct sbitmap_queue *sbq)
285{
286 struct sbq_wait_state *ws;
287 int wait_cnt;
288
289 /* Ensure that the wait list checks occur after clear_bit(). */
290 smp_mb();
291
292 ws = sbq_wake_ptr(sbq);
293 if (!ws)
294 return;
295
296 wait_cnt = atomic_dec_return(&ws->wait_cnt);
297 if (unlikely(wait_cnt < 0))
298 wait_cnt = atomic_inc_return(&ws->wait_cnt);
299 if (wait_cnt == 0) {
300 atomic_add(sbq->wake_batch, &ws->wait_cnt);
301 sbq_index_atomic_inc(&sbq->wake_index);
302 wake_up(&ws->wait);
303 }
304}
305
40aabb67
OS
306void sbitmap_queue_clear(struct sbitmap_queue *sbq, unsigned int nr,
307 bool round_robin, unsigned int cpu)
88459642
OS
308{
309 sbitmap_clear_bit(&sbq->sb, nr);
310 sbq_wake_up(sbq);
40aabb67
OS
311 if (likely(!round_robin))
312 *per_cpu_ptr(sbq->alloc_hint, cpu) = nr;
88459642
OS
313}
314EXPORT_SYMBOL_GPL(sbitmap_queue_clear);
315
316void sbitmap_queue_wake_all(struct sbitmap_queue *sbq)
317{
318 int i, wake_index;
319
320 /*
321 * Make sure all changes prior to this are visible from other CPUs.
322 */
323 smp_mb();
324 wake_index = atomic_read(&sbq->wake_index);
325 for (i = 0; i < SBQ_WAIT_QUEUES; i++) {
326 struct sbq_wait_state *ws = &sbq->ws[wake_index];
327
328 if (waitqueue_active(&ws->wait))
329 wake_up(&ws->wait);
330
331 wake_index = sbq_index_inc(wake_index);
332 }
333}
334EXPORT_SYMBOL_GPL(sbitmap_queue_wake_all);