162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2016 Facebook 462306a36Sopenharmony_ci * Copyright (C) 2013-2014 Jens Axboe 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/sched.h> 862306a36Sopenharmony_ci#include <linux/random.h> 962306a36Sopenharmony_ci#include <linux/sbitmap.h> 1062306a36Sopenharmony_ci#include <linux/seq_file.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistatic int init_alloc_hint(struct sbitmap *sb, gfp_t flags) 1362306a36Sopenharmony_ci{ 1462306a36Sopenharmony_ci unsigned depth = sb->depth; 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci sb->alloc_hint = alloc_percpu_gfp(unsigned int, flags); 1762306a36Sopenharmony_ci if (!sb->alloc_hint) 1862306a36Sopenharmony_ci return -ENOMEM; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci if (depth && !sb->round_robin) { 2162306a36Sopenharmony_ci int i; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci for_each_possible_cpu(i) 2462306a36Sopenharmony_ci *per_cpu_ptr(sb->alloc_hint, i) = get_random_u32_below(depth); 2562306a36Sopenharmony_ci } 2662306a36Sopenharmony_ci return 0; 2762306a36Sopenharmony_ci} 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic inline unsigned update_alloc_hint_before_get(struct sbitmap *sb, 3062306a36Sopenharmony_ci unsigned int depth) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci unsigned hint; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci hint = this_cpu_read(*sb->alloc_hint); 3562306a36Sopenharmony_ci if (unlikely(hint >= depth)) { 3662306a36Sopenharmony_ci hint = depth ? get_random_u32_below(depth) : 0; 3762306a36Sopenharmony_ci this_cpu_write(*sb->alloc_hint, hint); 3862306a36Sopenharmony_ci } 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci return hint; 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic inline void update_alloc_hint_after_get(struct sbitmap *sb, 4462306a36Sopenharmony_ci unsigned int depth, 4562306a36Sopenharmony_ci unsigned int hint, 4662306a36Sopenharmony_ci unsigned int nr) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci if (nr == -1) { 4962306a36Sopenharmony_ci /* If the map is full, a hint won't do us much good. */ 5062306a36Sopenharmony_ci this_cpu_write(*sb->alloc_hint, 0); 5162306a36Sopenharmony_ci } else if (nr == hint || unlikely(sb->round_robin)) { 5262306a36Sopenharmony_ci /* Only update the hint if we used it. */ 5362306a36Sopenharmony_ci hint = nr + 1; 5462306a36Sopenharmony_ci if (hint >= depth - 1) 5562306a36Sopenharmony_ci hint = 0; 5662306a36Sopenharmony_ci this_cpu_write(*sb->alloc_hint, hint); 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* 6162306a36Sopenharmony_ci * See if we have deferred clears that we can batch move 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_cistatic inline bool sbitmap_deferred_clear(struct sbitmap_word *map) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci unsigned long mask; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (!READ_ONCE(map->cleared)) 6862306a36Sopenharmony_ci return false; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* 7162306a36Sopenharmony_ci * First get a stable cleared mask, setting the old mask to 0. 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_ci mask = xchg(&map->cleared, 0); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci /* 7662306a36Sopenharmony_ci * Now clear the masked bits in our free word 7762306a36Sopenharmony_ci */ 7862306a36Sopenharmony_ci atomic_long_andnot(mask, (atomic_long_t *)&map->word); 7962306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(atomic_long_t) != sizeof(map->word)); 8062306a36Sopenharmony_ci return true; 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ciint sbitmap_init_node(struct sbitmap *sb, unsigned int depth, int shift, 8462306a36Sopenharmony_ci gfp_t flags, int node, bool round_robin, 8562306a36Sopenharmony_ci bool alloc_hint) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci unsigned int bits_per_word; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci if (shift < 0) 9062306a36Sopenharmony_ci shift = sbitmap_calculate_shift(depth); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci bits_per_word = 1U << shift; 9362306a36Sopenharmony_ci if (bits_per_word > BITS_PER_LONG) 9462306a36Sopenharmony_ci return -EINVAL; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci sb->shift = shift; 9762306a36Sopenharmony_ci sb->depth = depth; 9862306a36Sopenharmony_ci sb->map_nr = DIV_ROUND_UP(sb->depth, bits_per_word); 9962306a36Sopenharmony_ci sb->round_robin = round_robin; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci if (depth == 0) { 10262306a36Sopenharmony_ci sb->map = NULL; 10362306a36Sopenharmony_ci return 0; 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (alloc_hint) { 10762306a36Sopenharmony_ci if (init_alloc_hint(sb, flags)) 10862306a36Sopenharmony_ci return -ENOMEM; 10962306a36Sopenharmony_ci } else { 11062306a36Sopenharmony_ci sb->alloc_hint = NULL; 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci sb->map = kvzalloc_node(sb->map_nr * sizeof(*sb->map), flags, node); 11462306a36Sopenharmony_ci if (!sb->map) { 11562306a36Sopenharmony_ci free_percpu(sb->alloc_hint); 11662306a36Sopenharmony_ci return -ENOMEM; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci return 0; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sbitmap_init_node); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_civoid sbitmap_resize(struct sbitmap *sb, unsigned int depth) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci unsigned int bits_per_word = 1U << sb->shift; 12662306a36Sopenharmony_ci unsigned int i; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci for (i = 0; i < sb->map_nr; i++) 12962306a36Sopenharmony_ci sbitmap_deferred_clear(&sb->map[i]); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci sb->depth = depth; 13262306a36Sopenharmony_ci sb->map_nr = DIV_ROUND_UP(sb->depth, bits_per_word); 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sbitmap_resize); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic int __sbitmap_get_word(unsigned long *word, unsigned long depth, 13762306a36Sopenharmony_ci unsigned int hint, bool wrap) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci int nr; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci /* don't wrap if starting from 0 */ 14262306a36Sopenharmony_ci wrap = wrap && hint; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci while (1) { 14562306a36Sopenharmony_ci nr = find_next_zero_bit(word, depth, hint); 14662306a36Sopenharmony_ci if (unlikely(nr >= depth)) { 14762306a36Sopenharmony_ci /* 14862306a36Sopenharmony_ci * We started with an offset, and we didn't reset the 14962306a36Sopenharmony_ci * offset to 0 in a failure case, so start from 0 to 15062306a36Sopenharmony_ci * exhaust the map. 15162306a36Sopenharmony_ci */ 15262306a36Sopenharmony_ci if (hint && wrap) { 15362306a36Sopenharmony_ci hint = 0; 15462306a36Sopenharmony_ci continue; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci return -1; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (!test_and_set_bit_lock(nr, word)) 16062306a36Sopenharmony_ci break; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci hint = nr + 1; 16362306a36Sopenharmony_ci if (hint >= depth - 1) 16462306a36Sopenharmony_ci hint = 0; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci return nr; 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic int sbitmap_find_bit_in_word(struct sbitmap_word *map, 17162306a36Sopenharmony_ci unsigned int depth, 17262306a36Sopenharmony_ci unsigned int alloc_hint, 17362306a36Sopenharmony_ci bool wrap) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci int nr; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci do { 17862306a36Sopenharmony_ci nr = __sbitmap_get_word(&map->word, depth, 17962306a36Sopenharmony_ci alloc_hint, wrap); 18062306a36Sopenharmony_ci if (nr != -1) 18162306a36Sopenharmony_ci break; 18262306a36Sopenharmony_ci if (!sbitmap_deferred_clear(map)) 18362306a36Sopenharmony_ci break; 18462306a36Sopenharmony_ci } while (1); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci return nr; 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic int sbitmap_find_bit(struct sbitmap *sb, 19062306a36Sopenharmony_ci unsigned int depth, 19162306a36Sopenharmony_ci unsigned int index, 19262306a36Sopenharmony_ci unsigned int alloc_hint, 19362306a36Sopenharmony_ci bool wrap) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci unsigned int i; 19662306a36Sopenharmony_ci int nr = -1; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci for (i = 0; i < sb->map_nr; i++) { 19962306a36Sopenharmony_ci nr = sbitmap_find_bit_in_word(&sb->map[index], 20062306a36Sopenharmony_ci min_t(unsigned int, 20162306a36Sopenharmony_ci __map_depth(sb, index), 20262306a36Sopenharmony_ci depth), 20362306a36Sopenharmony_ci alloc_hint, wrap); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (nr != -1) { 20662306a36Sopenharmony_ci nr += index << sb->shift; 20762306a36Sopenharmony_ci break; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci /* Jump to next index. */ 21162306a36Sopenharmony_ci alloc_hint = 0; 21262306a36Sopenharmony_ci if (++index >= sb->map_nr) 21362306a36Sopenharmony_ci index = 0; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci return nr; 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic int __sbitmap_get(struct sbitmap *sb, unsigned int alloc_hint) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci unsigned int index; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci index = SB_NR_TO_INDEX(sb, alloc_hint); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci /* 22662306a36Sopenharmony_ci * Unless we're doing round robin tag allocation, just use the 22762306a36Sopenharmony_ci * alloc_hint to find the right word index. No point in looping 22862306a36Sopenharmony_ci * twice in find_next_zero_bit() for that case. 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_ci if (sb->round_robin) 23162306a36Sopenharmony_ci alloc_hint = SB_NR_TO_BIT(sb, alloc_hint); 23262306a36Sopenharmony_ci else 23362306a36Sopenharmony_ci alloc_hint = 0; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci return sbitmap_find_bit(sb, UINT_MAX, index, alloc_hint, 23662306a36Sopenharmony_ci !sb->round_robin); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ciint sbitmap_get(struct sbitmap *sb) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci int nr; 24262306a36Sopenharmony_ci unsigned int hint, depth; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci if (WARN_ON_ONCE(unlikely(!sb->alloc_hint))) 24562306a36Sopenharmony_ci return -1; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci depth = READ_ONCE(sb->depth); 24862306a36Sopenharmony_ci hint = update_alloc_hint_before_get(sb, depth); 24962306a36Sopenharmony_ci nr = __sbitmap_get(sb, hint); 25062306a36Sopenharmony_ci update_alloc_hint_after_get(sb, depth, hint, nr); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci return nr; 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sbitmap_get); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cistatic int __sbitmap_get_shallow(struct sbitmap *sb, 25762306a36Sopenharmony_ci unsigned int alloc_hint, 25862306a36Sopenharmony_ci unsigned long shallow_depth) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci unsigned int index; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci index = SB_NR_TO_INDEX(sb, alloc_hint); 26362306a36Sopenharmony_ci alloc_hint = SB_NR_TO_BIT(sb, alloc_hint); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci return sbitmap_find_bit(sb, shallow_depth, index, alloc_hint, true); 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ciint sbitmap_get_shallow(struct sbitmap *sb, unsigned long shallow_depth) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci int nr; 27162306a36Sopenharmony_ci unsigned int hint, depth; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (WARN_ON_ONCE(unlikely(!sb->alloc_hint))) 27462306a36Sopenharmony_ci return -1; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci depth = READ_ONCE(sb->depth); 27762306a36Sopenharmony_ci hint = update_alloc_hint_before_get(sb, depth); 27862306a36Sopenharmony_ci nr = __sbitmap_get_shallow(sb, hint, shallow_depth); 27962306a36Sopenharmony_ci update_alloc_hint_after_get(sb, depth, hint, nr); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci return nr; 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sbitmap_get_shallow); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cibool sbitmap_any_bit_set(const struct sbitmap *sb) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci unsigned int i; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci for (i = 0; i < sb->map_nr; i++) { 29062306a36Sopenharmony_ci if (sb->map[i].word & ~sb->map[i].cleared) 29162306a36Sopenharmony_ci return true; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci return false; 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sbitmap_any_bit_set); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic unsigned int __sbitmap_weight(const struct sbitmap *sb, bool set) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci unsigned int i, weight = 0; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci for (i = 0; i < sb->map_nr; i++) { 30262306a36Sopenharmony_ci const struct sbitmap_word *word = &sb->map[i]; 30362306a36Sopenharmony_ci unsigned int word_depth = __map_depth(sb, i); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci if (set) 30662306a36Sopenharmony_ci weight += bitmap_weight(&word->word, word_depth); 30762306a36Sopenharmony_ci else 30862306a36Sopenharmony_ci weight += bitmap_weight(&word->cleared, word_depth); 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci return weight; 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic unsigned int sbitmap_cleared(const struct sbitmap *sb) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci return __sbitmap_weight(sb, false); 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ciunsigned int sbitmap_weight(const struct sbitmap *sb) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci return __sbitmap_weight(sb, true) - sbitmap_cleared(sb); 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sbitmap_weight); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_civoid sbitmap_show(struct sbitmap *sb, struct seq_file *m) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci seq_printf(m, "depth=%u\n", sb->depth); 32762306a36Sopenharmony_ci seq_printf(m, "busy=%u\n", sbitmap_weight(sb)); 32862306a36Sopenharmony_ci seq_printf(m, "cleared=%u\n", sbitmap_cleared(sb)); 32962306a36Sopenharmony_ci seq_printf(m, "bits_per_word=%u\n", 1U << sb->shift); 33062306a36Sopenharmony_ci seq_printf(m, "map_nr=%u\n", sb->map_nr); 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sbitmap_show); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic inline void emit_byte(struct seq_file *m, unsigned int offset, u8 byte) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci if ((offset & 0xf) == 0) { 33762306a36Sopenharmony_ci if (offset != 0) 33862306a36Sopenharmony_ci seq_putc(m, '\n'); 33962306a36Sopenharmony_ci seq_printf(m, "%08x:", offset); 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci if ((offset & 0x1) == 0) 34262306a36Sopenharmony_ci seq_putc(m, ' '); 34362306a36Sopenharmony_ci seq_printf(m, "%02x", byte); 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_civoid sbitmap_bitmap_show(struct sbitmap *sb, struct seq_file *m) 34762306a36Sopenharmony_ci{ 34862306a36Sopenharmony_ci u8 byte = 0; 34962306a36Sopenharmony_ci unsigned int byte_bits = 0; 35062306a36Sopenharmony_ci unsigned int offset = 0; 35162306a36Sopenharmony_ci int i; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci for (i = 0; i < sb->map_nr; i++) { 35462306a36Sopenharmony_ci unsigned long word = READ_ONCE(sb->map[i].word); 35562306a36Sopenharmony_ci unsigned long cleared = READ_ONCE(sb->map[i].cleared); 35662306a36Sopenharmony_ci unsigned int word_bits = __map_depth(sb, i); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci word &= ~cleared; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci while (word_bits > 0) { 36162306a36Sopenharmony_ci unsigned int bits = min(8 - byte_bits, word_bits); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci byte |= (word & (BIT(bits) - 1)) << byte_bits; 36462306a36Sopenharmony_ci byte_bits += bits; 36562306a36Sopenharmony_ci if (byte_bits == 8) { 36662306a36Sopenharmony_ci emit_byte(m, offset, byte); 36762306a36Sopenharmony_ci byte = 0; 36862306a36Sopenharmony_ci byte_bits = 0; 36962306a36Sopenharmony_ci offset++; 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci word >>= bits; 37262306a36Sopenharmony_ci word_bits -= bits; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci if (byte_bits) { 37662306a36Sopenharmony_ci emit_byte(m, offset, byte); 37762306a36Sopenharmony_ci offset++; 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci if (offset) 38062306a36Sopenharmony_ci seq_putc(m, '\n'); 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sbitmap_bitmap_show); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic unsigned int sbq_calc_wake_batch(struct sbitmap_queue *sbq, 38562306a36Sopenharmony_ci unsigned int depth) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci unsigned int wake_batch; 38862306a36Sopenharmony_ci unsigned int shallow_depth; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci /* 39162306a36Sopenharmony_ci * For each batch, we wake up one queue. We need to make sure that our 39262306a36Sopenharmony_ci * batch size is small enough that the full depth of the bitmap, 39362306a36Sopenharmony_ci * potentially limited by a shallow depth, is enough to wake up all of 39462306a36Sopenharmony_ci * the queues. 39562306a36Sopenharmony_ci * 39662306a36Sopenharmony_ci * Each full word of the bitmap has bits_per_word bits, and there might 39762306a36Sopenharmony_ci * be a partial word. There are depth / bits_per_word full words and 39862306a36Sopenharmony_ci * depth % bits_per_word bits left over. In bitwise arithmetic: 39962306a36Sopenharmony_ci * 40062306a36Sopenharmony_ci * bits_per_word = 1 << shift 40162306a36Sopenharmony_ci * depth / bits_per_word = depth >> shift 40262306a36Sopenharmony_ci * depth % bits_per_word = depth & ((1 << shift) - 1) 40362306a36Sopenharmony_ci * 40462306a36Sopenharmony_ci * Each word can be limited to sbq->min_shallow_depth bits. 40562306a36Sopenharmony_ci */ 40662306a36Sopenharmony_ci shallow_depth = min(1U << sbq->sb.shift, sbq->min_shallow_depth); 40762306a36Sopenharmony_ci depth = ((depth >> sbq->sb.shift) * shallow_depth + 40862306a36Sopenharmony_ci min(depth & ((1U << sbq->sb.shift) - 1), shallow_depth)); 40962306a36Sopenharmony_ci wake_batch = clamp_t(unsigned int, depth / SBQ_WAIT_QUEUES, 1, 41062306a36Sopenharmony_ci SBQ_WAKE_BATCH); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci return wake_batch; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ciint sbitmap_queue_init_node(struct sbitmap_queue *sbq, unsigned int depth, 41662306a36Sopenharmony_ci int shift, bool round_robin, gfp_t flags, int node) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci int ret; 41962306a36Sopenharmony_ci int i; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci ret = sbitmap_init_node(&sbq->sb, depth, shift, flags, node, 42262306a36Sopenharmony_ci round_robin, true); 42362306a36Sopenharmony_ci if (ret) 42462306a36Sopenharmony_ci return ret; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci sbq->min_shallow_depth = UINT_MAX; 42762306a36Sopenharmony_ci sbq->wake_batch = sbq_calc_wake_batch(sbq, depth); 42862306a36Sopenharmony_ci atomic_set(&sbq->wake_index, 0); 42962306a36Sopenharmony_ci atomic_set(&sbq->ws_active, 0); 43062306a36Sopenharmony_ci atomic_set(&sbq->completion_cnt, 0); 43162306a36Sopenharmony_ci atomic_set(&sbq->wakeup_cnt, 0); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci sbq->ws = kzalloc_node(SBQ_WAIT_QUEUES * sizeof(*sbq->ws), flags, node); 43462306a36Sopenharmony_ci if (!sbq->ws) { 43562306a36Sopenharmony_ci sbitmap_free(&sbq->sb); 43662306a36Sopenharmony_ci return -ENOMEM; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci for (i = 0; i < SBQ_WAIT_QUEUES; i++) 44062306a36Sopenharmony_ci init_waitqueue_head(&sbq->ws[i].wait); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci return 0; 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sbitmap_queue_init_node); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic void sbitmap_queue_update_wake_batch(struct sbitmap_queue *sbq, 44762306a36Sopenharmony_ci unsigned int depth) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci unsigned int wake_batch; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci wake_batch = sbq_calc_wake_batch(sbq, depth); 45262306a36Sopenharmony_ci if (sbq->wake_batch != wake_batch) 45362306a36Sopenharmony_ci WRITE_ONCE(sbq->wake_batch, wake_batch); 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_civoid sbitmap_queue_recalculate_wake_batch(struct sbitmap_queue *sbq, 45762306a36Sopenharmony_ci unsigned int users) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci unsigned int wake_batch; 46062306a36Sopenharmony_ci unsigned int depth = (sbq->sb.depth + users - 1) / users; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci wake_batch = clamp_val(depth / SBQ_WAIT_QUEUES, 46362306a36Sopenharmony_ci 1, SBQ_WAKE_BATCH); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci WRITE_ONCE(sbq->wake_batch, wake_batch); 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sbitmap_queue_recalculate_wake_batch); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_civoid sbitmap_queue_resize(struct sbitmap_queue *sbq, unsigned int depth) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci sbitmap_queue_update_wake_batch(sbq, depth); 47262306a36Sopenharmony_ci sbitmap_resize(&sbq->sb, depth); 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sbitmap_queue_resize); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ciint __sbitmap_queue_get(struct sbitmap_queue *sbq) 47762306a36Sopenharmony_ci{ 47862306a36Sopenharmony_ci return sbitmap_get(&sbq->sb); 47962306a36Sopenharmony_ci} 48062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__sbitmap_queue_get); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ciunsigned long __sbitmap_queue_get_batch(struct sbitmap_queue *sbq, int nr_tags, 48362306a36Sopenharmony_ci unsigned int *offset) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci struct sbitmap *sb = &sbq->sb; 48662306a36Sopenharmony_ci unsigned int hint, depth; 48762306a36Sopenharmony_ci unsigned long index, nr; 48862306a36Sopenharmony_ci int i; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci if (unlikely(sb->round_robin)) 49162306a36Sopenharmony_ci return 0; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci depth = READ_ONCE(sb->depth); 49462306a36Sopenharmony_ci hint = update_alloc_hint_before_get(sb, depth); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci index = SB_NR_TO_INDEX(sb, hint); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci for (i = 0; i < sb->map_nr; i++) { 49962306a36Sopenharmony_ci struct sbitmap_word *map = &sb->map[index]; 50062306a36Sopenharmony_ci unsigned long get_mask; 50162306a36Sopenharmony_ci unsigned int map_depth = __map_depth(sb, index); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci sbitmap_deferred_clear(map); 50462306a36Sopenharmony_ci if (map->word == (1UL << (map_depth - 1)) - 1) 50562306a36Sopenharmony_ci goto next; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci nr = find_first_zero_bit(&map->word, map_depth); 50862306a36Sopenharmony_ci if (nr + nr_tags <= map_depth) { 50962306a36Sopenharmony_ci atomic_long_t *ptr = (atomic_long_t *) &map->word; 51062306a36Sopenharmony_ci unsigned long val; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci get_mask = ((1UL << nr_tags) - 1) << nr; 51362306a36Sopenharmony_ci val = READ_ONCE(map->word); 51462306a36Sopenharmony_ci while (!atomic_long_try_cmpxchg(ptr, &val, 51562306a36Sopenharmony_ci get_mask | val)) 51662306a36Sopenharmony_ci ; 51762306a36Sopenharmony_ci get_mask = (get_mask & ~val) >> nr; 51862306a36Sopenharmony_ci if (get_mask) { 51962306a36Sopenharmony_ci *offset = nr + (index << sb->shift); 52062306a36Sopenharmony_ci update_alloc_hint_after_get(sb, depth, hint, 52162306a36Sopenharmony_ci *offset + nr_tags - 1); 52262306a36Sopenharmony_ci return get_mask; 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_cinext: 52662306a36Sopenharmony_ci /* Jump to next index. */ 52762306a36Sopenharmony_ci if (++index >= sb->map_nr) 52862306a36Sopenharmony_ci index = 0; 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci return 0; 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ciint sbitmap_queue_get_shallow(struct sbitmap_queue *sbq, 53562306a36Sopenharmony_ci unsigned int shallow_depth) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci WARN_ON_ONCE(shallow_depth < sbq->min_shallow_depth); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci return sbitmap_get_shallow(&sbq->sb, shallow_depth); 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sbitmap_queue_get_shallow); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_civoid sbitmap_queue_min_shallow_depth(struct sbitmap_queue *sbq, 54462306a36Sopenharmony_ci unsigned int min_shallow_depth) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci sbq->min_shallow_depth = min_shallow_depth; 54762306a36Sopenharmony_ci sbitmap_queue_update_wake_batch(sbq, sbq->sb.depth); 54862306a36Sopenharmony_ci} 54962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sbitmap_queue_min_shallow_depth); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cistatic void __sbitmap_queue_wake_up(struct sbitmap_queue *sbq, int nr) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci int i, wake_index, woken; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci if (!atomic_read(&sbq->ws_active)) 55662306a36Sopenharmony_ci return; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci wake_index = atomic_read(&sbq->wake_index); 55962306a36Sopenharmony_ci for (i = 0; i < SBQ_WAIT_QUEUES; i++) { 56062306a36Sopenharmony_ci struct sbq_wait_state *ws = &sbq->ws[wake_index]; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci /* 56362306a36Sopenharmony_ci * Advance the index before checking the current queue. 56462306a36Sopenharmony_ci * It improves fairness, by ensuring the queue doesn't 56562306a36Sopenharmony_ci * need to be fully emptied before trying to wake up 56662306a36Sopenharmony_ci * from the next one. 56762306a36Sopenharmony_ci */ 56862306a36Sopenharmony_ci wake_index = sbq_index_inc(wake_index); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci if (waitqueue_active(&ws->wait)) { 57162306a36Sopenharmony_ci woken = wake_up_nr(&ws->wait, nr); 57262306a36Sopenharmony_ci if (woken == nr) 57362306a36Sopenharmony_ci break; 57462306a36Sopenharmony_ci nr -= woken; 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci if (wake_index != atomic_read(&sbq->wake_index)) 57962306a36Sopenharmony_ci atomic_set(&sbq->wake_index, wake_index); 58062306a36Sopenharmony_ci} 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_civoid sbitmap_queue_wake_up(struct sbitmap_queue *sbq, int nr) 58362306a36Sopenharmony_ci{ 58462306a36Sopenharmony_ci unsigned int wake_batch = READ_ONCE(sbq->wake_batch); 58562306a36Sopenharmony_ci unsigned int wakeups; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci if (!atomic_read(&sbq->ws_active)) 58862306a36Sopenharmony_ci return; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci atomic_add(nr, &sbq->completion_cnt); 59162306a36Sopenharmony_ci wakeups = atomic_read(&sbq->wakeup_cnt); 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci do { 59462306a36Sopenharmony_ci if (atomic_read(&sbq->completion_cnt) - wakeups < wake_batch) 59562306a36Sopenharmony_ci return; 59662306a36Sopenharmony_ci } while (!atomic_try_cmpxchg(&sbq->wakeup_cnt, 59762306a36Sopenharmony_ci &wakeups, wakeups + wake_batch)); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci __sbitmap_queue_wake_up(sbq, wake_batch); 60062306a36Sopenharmony_ci} 60162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sbitmap_queue_wake_up); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_cistatic inline void sbitmap_update_cpu_hint(struct sbitmap *sb, int cpu, int tag) 60462306a36Sopenharmony_ci{ 60562306a36Sopenharmony_ci if (likely(!sb->round_robin && tag < sb->depth)) 60662306a36Sopenharmony_ci data_race(*per_cpu_ptr(sb->alloc_hint, cpu) = tag); 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_civoid sbitmap_queue_clear_batch(struct sbitmap_queue *sbq, int offset, 61062306a36Sopenharmony_ci int *tags, int nr_tags) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci struct sbitmap *sb = &sbq->sb; 61362306a36Sopenharmony_ci unsigned long *addr = NULL; 61462306a36Sopenharmony_ci unsigned long mask = 0; 61562306a36Sopenharmony_ci int i; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci smp_mb__before_atomic(); 61862306a36Sopenharmony_ci for (i = 0; i < nr_tags; i++) { 61962306a36Sopenharmony_ci const int tag = tags[i] - offset; 62062306a36Sopenharmony_ci unsigned long *this_addr; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci /* since we're clearing a batch, skip the deferred map */ 62362306a36Sopenharmony_ci this_addr = &sb->map[SB_NR_TO_INDEX(sb, tag)].word; 62462306a36Sopenharmony_ci if (!addr) { 62562306a36Sopenharmony_ci addr = this_addr; 62662306a36Sopenharmony_ci } else if (addr != this_addr) { 62762306a36Sopenharmony_ci atomic_long_andnot(mask, (atomic_long_t *) addr); 62862306a36Sopenharmony_ci mask = 0; 62962306a36Sopenharmony_ci addr = this_addr; 63062306a36Sopenharmony_ci } 63162306a36Sopenharmony_ci mask |= (1UL << SB_NR_TO_BIT(sb, tag)); 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci if (mask) 63562306a36Sopenharmony_ci atomic_long_andnot(mask, (atomic_long_t *) addr); 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci smp_mb__after_atomic(); 63862306a36Sopenharmony_ci sbitmap_queue_wake_up(sbq, nr_tags); 63962306a36Sopenharmony_ci sbitmap_update_cpu_hint(&sbq->sb, raw_smp_processor_id(), 64062306a36Sopenharmony_ci tags[nr_tags - 1] - offset); 64162306a36Sopenharmony_ci} 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_civoid sbitmap_queue_clear(struct sbitmap_queue *sbq, unsigned int nr, 64462306a36Sopenharmony_ci unsigned int cpu) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci /* 64762306a36Sopenharmony_ci * Once the clear bit is set, the bit may be allocated out. 64862306a36Sopenharmony_ci * 64962306a36Sopenharmony_ci * Orders READ/WRITE on the associated instance(such as request 65062306a36Sopenharmony_ci * of blk_mq) by this bit for avoiding race with re-allocation, 65162306a36Sopenharmony_ci * and its pair is the memory barrier implied in __sbitmap_get_word. 65262306a36Sopenharmony_ci * 65362306a36Sopenharmony_ci * One invariant is that the clear bit has to be zero when the bit 65462306a36Sopenharmony_ci * is in use. 65562306a36Sopenharmony_ci */ 65662306a36Sopenharmony_ci smp_mb__before_atomic(); 65762306a36Sopenharmony_ci sbitmap_deferred_clear_bit(&sbq->sb, nr); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci /* 66062306a36Sopenharmony_ci * Pairs with the memory barrier in set_current_state() to ensure the 66162306a36Sopenharmony_ci * proper ordering of clear_bit_unlock()/waitqueue_active() in the waker 66262306a36Sopenharmony_ci * and test_and_set_bit_lock()/prepare_to_wait()/finish_wait() in the 66362306a36Sopenharmony_ci * waiter. See the comment on waitqueue_active(). 66462306a36Sopenharmony_ci */ 66562306a36Sopenharmony_ci smp_mb__after_atomic(); 66662306a36Sopenharmony_ci sbitmap_queue_wake_up(sbq, 1); 66762306a36Sopenharmony_ci sbitmap_update_cpu_hint(&sbq->sb, cpu, nr); 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sbitmap_queue_clear); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_civoid sbitmap_queue_wake_all(struct sbitmap_queue *sbq) 67262306a36Sopenharmony_ci{ 67362306a36Sopenharmony_ci int i, wake_index; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci /* 67662306a36Sopenharmony_ci * Pairs with the memory barrier in set_current_state() like in 67762306a36Sopenharmony_ci * sbitmap_queue_wake_up(). 67862306a36Sopenharmony_ci */ 67962306a36Sopenharmony_ci smp_mb(); 68062306a36Sopenharmony_ci wake_index = atomic_read(&sbq->wake_index); 68162306a36Sopenharmony_ci for (i = 0; i < SBQ_WAIT_QUEUES; i++) { 68262306a36Sopenharmony_ci struct sbq_wait_state *ws = &sbq->ws[wake_index]; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci if (waitqueue_active(&ws->wait)) 68562306a36Sopenharmony_ci wake_up(&ws->wait); 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci wake_index = sbq_index_inc(wake_index); 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci} 69062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sbitmap_queue_wake_all); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_civoid sbitmap_queue_show(struct sbitmap_queue *sbq, struct seq_file *m) 69362306a36Sopenharmony_ci{ 69462306a36Sopenharmony_ci bool first; 69562306a36Sopenharmony_ci int i; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci sbitmap_show(&sbq->sb, m); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci seq_puts(m, "alloc_hint={"); 70062306a36Sopenharmony_ci first = true; 70162306a36Sopenharmony_ci for_each_possible_cpu(i) { 70262306a36Sopenharmony_ci if (!first) 70362306a36Sopenharmony_ci seq_puts(m, ", "); 70462306a36Sopenharmony_ci first = false; 70562306a36Sopenharmony_ci seq_printf(m, "%u", *per_cpu_ptr(sbq->sb.alloc_hint, i)); 70662306a36Sopenharmony_ci } 70762306a36Sopenharmony_ci seq_puts(m, "}\n"); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci seq_printf(m, "wake_batch=%u\n", sbq->wake_batch); 71062306a36Sopenharmony_ci seq_printf(m, "wake_index=%d\n", atomic_read(&sbq->wake_index)); 71162306a36Sopenharmony_ci seq_printf(m, "ws_active=%d\n", atomic_read(&sbq->ws_active)); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci seq_puts(m, "ws={\n"); 71462306a36Sopenharmony_ci for (i = 0; i < SBQ_WAIT_QUEUES; i++) { 71562306a36Sopenharmony_ci struct sbq_wait_state *ws = &sbq->ws[i]; 71662306a36Sopenharmony_ci seq_printf(m, "\t{.wait=%s},\n", 71762306a36Sopenharmony_ci waitqueue_active(&ws->wait) ? "active" : "inactive"); 71862306a36Sopenharmony_ci } 71962306a36Sopenharmony_ci seq_puts(m, "}\n"); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci seq_printf(m, "round_robin=%d\n", sbq->sb.round_robin); 72262306a36Sopenharmony_ci seq_printf(m, "min_shallow_depth=%u\n", sbq->min_shallow_depth); 72362306a36Sopenharmony_ci} 72462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sbitmap_queue_show); 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_civoid sbitmap_add_wait_queue(struct sbitmap_queue *sbq, 72762306a36Sopenharmony_ci struct sbq_wait_state *ws, 72862306a36Sopenharmony_ci struct sbq_wait *sbq_wait) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci if (!sbq_wait->sbq) { 73162306a36Sopenharmony_ci sbq_wait->sbq = sbq; 73262306a36Sopenharmony_ci atomic_inc(&sbq->ws_active); 73362306a36Sopenharmony_ci add_wait_queue(&ws->wait, &sbq_wait->wait); 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci} 73662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sbitmap_add_wait_queue); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_civoid sbitmap_del_wait_queue(struct sbq_wait *sbq_wait) 73962306a36Sopenharmony_ci{ 74062306a36Sopenharmony_ci list_del_init(&sbq_wait->wait.entry); 74162306a36Sopenharmony_ci if (sbq_wait->sbq) { 74262306a36Sopenharmony_ci atomic_dec(&sbq_wait->sbq->ws_active); 74362306a36Sopenharmony_ci sbq_wait->sbq = NULL; 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sbitmap_del_wait_queue); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_civoid sbitmap_prepare_to_wait(struct sbitmap_queue *sbq, 74962306a36Sopenharmony_ci struct sbq_wait_state *ws, 75062306a36Sopenharmony_ci struct sbq_wait *sbq_wait, int state) 75162306a36Sopenharmony_ci{ 75262306a36Sopenharmony_ci if (!sbq_wait->sbq) { 75362306a36Sopenharmony_ci atomic_inc(&sbq->ws_active); 75462306a36Sopenharmony_ci sbq_wait->sbq = sbq; 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci prepare_to_wait_exclusive(&ws->wait, &sbq_wait->wait, state); 75762306a36Sopenharmony_ci} 75862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sbitmap_prepare_to_wait); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_civoid sbitmap_finish_wait(struct sbitmap_queue *sbq, struct sbq_wait_state *ws, 76162306a36Sopenharmony_ci struct sbq_wait *sbq_wait) 76262306a36Sopenharmony_ci{ 76362306a36Sopenharmony_ci finish_wait(&ws->wait, &sbq_wait->wait); 76462306a36Sopenharmony_ci if (sbq_wait->sbq) { 76562306a36Sopenharmony_ci atomic_dec(&sbq->ws_active); 76662306a36Sopenharmony_ci sbq_wait->sbq = NULL; 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci} 76962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(sbitmap_finish_wait); 770