aboutsummaryrefslogtreecommitdiffstats
path: root/lib/sbitmap.c
diff options
context:
space:
mode:
authorOmar Sandoval <osandov@fb.com>2017-04-14 03:59:58 -0400
committerJens Axboe <axboe@fb.com>2017-04-14 16:06:52 -0400
commitc05e66733788118377c21a913c1bc7b64bccc167 (patch)
tree8c13d6e75fe1ceac7db6f1cb5b7723ba5fe742b7 /lib/sbitmap.c
parent84253394927c4352652d0b118ad9583f5646959b (diff)
sbitmap: add sbitmap_get_shallow() operation
This operation supports the use case of limiting the number of bits that can be allocated for a given operation. Rather than setting aside some bits at the end of the bitmap, we can set aside bits in each word of the bitmap. This means we can keep the allocation hints spread out and support sbitmap_resize() nicely at the cost of lower granularity for the allowed depth. Signed-off-by: Omar Sandoval <osandov@fb.com> Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'lib/sbitmap.c')
-rw-r--r--lib/sbitmap.c75
1 files changed, 68 insertions, 7 deletions
diff --git a/lib/sbitmap.c b/lib/sbitmap.c
index 60e800e0b5a0..80aa8d5463fa 100644
--- a/lib/sbitmap.c
+++ b/lib/sbitmap.c
@@ -79,15 +79,15 @@ void sbitmap_resize(struct sbitmap *sb, unsigned int depth)
79} 79}
80EXPORT_SYMBOL_GPL(sbitmap_resize); 80EXPORT_SYMBOL_GPL(sbitmap_resize);
81 81
82static int __sbitmap_get_word(struct sbitmap_word *word, unsigned int hint, 82static int __sbitmap_get_word(unsigned long *word, unsigned long depth,
83 bool wrap) 83 unsigned int hint, bool wrap)
84{ 84{
85 unsigned int orig_hint = hint; 85 unsigned int orig_hint = hint;
86 int nr; 86 int nr;
87 87
88 while (1) { 88 while (1) {
89 nr = find_next_zero_bit(&word->word, word->depth, hint); 89 nr = find_next_zero_bit(word, depth, hint);
90 if (unlikely(nr >= word->depth)) { 90 if (unlikely(nr >= depth)) {
91 /* 91 /*
92 * We started with an offset, and we didn't reset the 92 * We started with an offset, and we didn't reset the
93 * offset to 0 in a failure case, so start from 0 to 93 * offset to 0 in a failure case, so start from 0 to
@@ -100,11 +100,11 @@ static int __sbitmap_get_word(struct sbitmap_word *word, unsigned int hint,
100 return -1; 100 return -1;
101 } 101 }
102 102
103 if (!test_and_set_bit(nr, &word->word)) 103 if (!test_and_set_bit(nr, word))
104 break; 104 break;
105 105
106 hint = nr + 1; 106 hint = nr + 1;
107 if (hint >= word->depth - 1) 107 if (hint >= depth - 1)
108 hint = 0; 108 hint = 0;
109 } 109 }
110 110
@@ -119,7 +119,8 @@ int sbitmap_get(struct sbitmap *sb, unsigned int alloc_hint, bool round_robin)
119 index = SB_NR_TO_INDEX(sb, alloc_hint); 119 index = SB_NR_TO_INDEX(sb, alloc_hint);
120 120
121 for (i = 0; i < sb->map_nr; i++) { 121 for (i = 0; i < sb->map_nr; i++) {
122 nr = __sbitmap_get_word(&sb->map[index], 122 nr = __sbitmap_get_word(&sb->map[index].word,
123 sb->map[index].depth,
123 SB_NR_TO_BIT(sb, alloc_hint), 124 SB_NR_TO_BIT(sb, alloc_hint),
124 !round_robin); 125 !round_robin);
125 if (nr != -1) { 126 if (nr != -1) {
@@ -141,6 +142,37 @@ int sbitmap_get(struct sbitmap *sb, unsigned int alloc_hint, bool round_robin)
141} 142}
142EXPORT_SYMBOL_GPL(sbitmap_get); 143EXPORT_SYMBOL_GPL(sbitmap_get);
143 144
145int sbitmap_get_shallow(struct sbitmap *sb, unsigned int alloc_hint,
146 unsigned long shallow_depth)
147{
148 unsigned int i, index;
149 int nr = -1;
150
151 index = SB_NR_TO_INDEX(sb, alloc_hint);
152
153 for (i = 0; i < sb->map_nr; i++) {
154 nr = __sbitmap_get_word(&sb->map[index].word,
155 min(sb->map[index].depth, shallow_depth),
156 SB_NR_TO_BIT(sb, alloc_hint), true);
157 if (nr != -1) {
158 nr += index << sb->shift;
159 break;
160 }
161
162 /* Jump to next index. */
163 index++;
164 alloc_hint = index << sb->shift;
165
166 if (index >= sb->map_nr) {
167 index = 0;
168 alloc_hint = 0;
169 }
170 }
171
172 return nr;
173}
174EXPORT_SYMBOL_GPL(sbitmap_get_shallow);
175
144bool sbitmap_any_bit_set(const struct sbitmap *sb) 176bool sbitmap_any_bit_set(const struct sbitmap *sb)
145{ 177{
146 unsigned int i; 178 unsigned int i;
@@ -342,6 +374,35 @@ int __sbitmap_queue_get(struct sbitmap_queue *sbq)
342} 374}
343EXPORT_SYMBOL_GPL(__sbitmap_queue_get); 375EXPORT_SYMBOL_GPL(__sbitmap_queue_get);
344 376
377int __sbitmap_queue_get_shallow(struct sbitmap_queue *sbq,
378 unsigned int shallow_depth)
379{
380 unsigned int hint, depth;
381 int nr;
382
383 hint = this_cpu_read(*sbq->alloc_hint);
384 depth = READ_ONCE(sbq->sb.depth);
385 if (unlikely(hint >= depth)) {
386 hint = depth ? prandom_u32() % depth : 0;
387 this_cpu_write(*sbq->alloc_hint, hint);
388 }
389 nr = sbitmap_get_shallow(&sbq->sb, hint, shallow_depth);
390
391 if (nr == -1) {
392 /* If the map is full, a hint won't do us much good. */
393 this_cpu_write(*sbq->alloc_hint, 0);
394 } else if (nr == hint || unlikely(sbq->round_robin)) {
395 /* Only update the hint if we used it. */
396 hint = nr + 1;
397 if (hint >= depth - 1)
398 hint = 0;
399 this_cpu_write(*sbq->alloc_hint, hint);
400 }
401
402 return nr;
403}
404EXPORT_SYMBOL_GPL(__sbitmap_queue_get_shallow);
405
345static struct sbq_wait_state *sbq_wake_ptr(struct sbitmap_queue *sbq) 406static struct sbq_wait_state *sbq_wake_ptr(struct sbitmap_queue *sbq)
346{ 407{
347 int i, wake_index; 408 int i, wake_index;