xref: /kernel/linux/linux-6.6/lib/sbitmap.c (revision 62306a36)
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