diff options
Diffstat (limited to 'lib/sbitmap.c')
| -rw-r--r-- | lib/sbitmap.c | 75 |
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 | } |
| 80 | EXPORT_SYMBOL_GPL(sbitmap_resize); | 80 | EXPORT_SYMBOL_GPL(sbitmap_resize); |
| 81 | 81 | ||
| 82 | static int __sbitmap_get_word(struct sbitmap_word *word, unsigned int hint, | 82 | static 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 | } |
| 142 | EXPORT_SYMBOL_GPL(sbitmap_get); | 143 | EXPORT_SYMBOL_GPL(sbitmap_get); |
| 143 | 144 | ||
| 145 | int 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 | } | ||
| 174 | EXPORT_SYMBOL_GPL(sbitmap_get_shallow); | ||
| 175 | |||
| 144 | bool sbitmap_any_bit_set(const struct sbitmap *sb) | 176 | bool 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 | } |
| 343 | EXPORT_SYMBOL_GPL(__sbitmap_queue_get); | 375 | EXPORT_SYMBOL_GPL(__sbitmap_queue_get); |
| 344 | 376 | ||
| 377 | int __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 | } | ||
| 404 | EXPORT_SYMBOL_GPL(__sbitmap_queue_get_shallow); | ||
| 405 | |||
| 345 | static struct sbq_wait_state *sbq_wake_ptr(struct sbitmap_queue *sbq) | 406 | static struct sbq_wait_state *sbq_wake_ptr(struct sbitmap_queue *sbq) |
| 346 | { | 407 | { |
| 347 | int i, wake_index; | 408 | int i, wake_index; |
