| .. | .. |
|---|
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Fast and scalable bitmaps. |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2016 Facebook |
|---|
| 5 | 6 | * Copyright (C) 2013-2014 Jens Axboe |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or |
|---|
| 8 | | - * modify it under the terms of the GNU General Public |
|---|
| 9 | | - * License v2 as published by the Free Software Foundation. |
|---|
| 10 | | - * |
|---|
| 11 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 12 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 14 | | - * General Public License for more details. |
|---|
| 15 | | - * |
|---|
| 16 | | - * You should have received a copy of the GNU General Public License |
|---|
| 17 | | - * along with this program. If not, see <https://www.gnu.org/licenses/>. |
|---|
| 18 | 7 | */ |
|---|
| 19 | 8 | |
|---|
| 20 | 9 | #ifndef __LINUX_SCALE_BITMAP_H |
|---|
| .. | .. |
|---|
| 30 | 19 | */ |
|---|
| 31 | 20 | struct sbitmap_word { |
|---|
| 32 | 21 | /** |
|---|
| 33 | | - * @word: The bitmap word itself. |
|---|
| 34 | | - */ |
|---|
| 35 | | - unsigned long word; |
|---|
| 36 | | - |
|---|
| 37 | | - /** |
|---|
| 38 | | - * @depth: Number of bits being used in @word. |
|---|
| 22 | + * @depth: Number of bits being used in @word/@cleared |
|---|
| 39 | 23 | */ |
|---|
| 40 | 24 | unsigned long depth; |
|---|
| 25 | + |
|---|
| 26 | + /** |
|---|
| 27 | + * @word: word holding free bits |
|---|
| 28 | + */ |
|---|
| 29 | + unsigned long word ____cacheline_aligned_in_smp; |
|---|
| 30 | + |
|---|
| 31 | + /** |
|---|
| 32 | + * @cleared: word holding cleared bits |
|---|
| 33 | + */ |
|---|
| 34 | + unsigned long cleared ____cacheline_aligned_in_smp; |
|---|
| 35 | + |
|---|
| 36 | + /** |
|---|
| 37 | + * @swap_lock: Held while swapping word <-> cleared |
|---|
| 38 | + */ |
|---|
| 39 | + spinlock_t swap_lock; |
|---|
| 41 | 40 | } ____cacheline_aligned_in_smp; |
|---|
| 42 | 41 | |
|---|
| 43 | 42 | /** |
|---|
| .. | .. |
|---|
| 124 | 123 | * @ws: Wait queues. |
|---|
| 125 | 124 | */ |
|---|
| 126 | 125 | struct sbq_wait_state *ws; |
|---|
| 126 | + |
|---|
| 127 | + /* |
|---|
| 128 | + * @ws_active: count of currently active ws waitqueues |
|---|
| 129 | + */ |
|---|
| 130 | + atomic_t ws_active; |
|---|
| 127 | 131 | |
|---|
| 128 | 132 | /** |
|---|
| 129 | 133 | * @round_robin: Allocate bits in strict round-robin order. |
|---|
| .. | .. |
|---|
| 212 | 216 | */ |
|---|
| 213 | 217 | bool sbitmap_any_bit_set(const struct sbitmap *sb); |
|---|
| 214 | 218 | |
|---|
| 215 | | -/** |
|---|
| 216 | | - * sbitmap_any_bit_clear() - Check for an unset bit in a &struct |
|---|
| 217 | | - * sbitmap. |
|---|
| 218 | | - * @sb: Bitmap to check. |
|---|
| 219 | | - * |
|---|
| 220 | | - * Return: true if any bit in the bitmap is clear, false otherwise. |
|---|
| 221 | | - */ |
|---|
| 222 | | -bool sbitmap_any_bit_clear(const struct sbitmap *sb); |
|---|
| 223 | | - |
|---|
| 224 | 219 | #define SB_NR_TO_INDEX(sb, bitnr) ((bitnr) >> (sb)->shift) |
|---|
| 225 | 220 | #define SB_NR_TO_BIT(sb, bitnr) ((bitnr) & ((1U << (sb)->shift) - 1U)) |
|---|
| 226 | 221 | |
|---|
| .. | .. |
|---|
| 250 | 245 | nr = SB_NR_TO_BIT(sb, start); |
|---|
| 251 | 246 | |
|---|
| 252 | 247 | while (scanned < sb->depth) { |
|---|
| 253 | | - struct sbitmap_word *word = &sb->map[index]; |
|---|
| 254 | | - unsigned int depth = min_t(unsigned int, word->depth - nr, |
|---|
| 248 | + unsigned long word; |
|---|
| 249 | + unsigned int depth = min_t(unsigned int, |
|---|
| 250 | + sb->map[index].depth - nr, |
|---|
| 255 | 251 | sb->depth - scanned); |
|---|
| 256 | 252 | |
|---|
| 257 | 253 | scanned += depth; |
|---|
| 258 | | - if (!word->word) |
|---|
| 254 | + word = sb->map[index].word & ~sb->map[index].cleared; |
|---|
| 255 | + if (!word) |
|---|
| 259 | 256 | goto next; |
|---|
| 260 | 257 | |
|---|
| 261 | 258 | /* |
|---|
| .. | .. |
|---|
| 265 | 262 | */ |
|---|
| 266 | 263 | depth += nr; |
|---|
| 267 | 264 | while (1) { |
|---|
| 268 | | - nr = find_next_bit(&word->word, depth, nr); |
|---|
| 265 | + nr = find_next_bit(&word, depth, nr); |
|---|
| 269 | 266 | if (nr >= depth) |
|---|
| 270 | 267 | break; |
|---|
| 271 | 268 | if (!fn(sb, (index << sb->shift) + nr, data)) |
|---|
| .. | .. |
|---|
| 310 | 307 | clear_bit(SB_NR_TO_BIT(sb, bitnr), __sbitmap_word(sb, bitnr)); |
|---|
| 311 | 308 | } |
|---|
| 312 | 309 | |
|---|
| 310 | +/* |
|---|
| 311 | + * This one is special, since it doesn't actually clear the bit, rather it |
|---|
| 312 | + * sets the corresponding bit in the ->cleared mask instead. Paired with |
|---|
| 313 | + * the caller doing sbitmap_deferred_clear() if a given index is full, which |
|---|
| 314 | + * will clear the previously freed entries in the corresponding ->word. |
|---|
| 315 | + */ |
|---|
| 316 | +static inline void sbitmap_deferred_clear_bit(struct sbitmap *sb, unsigned int bitnr) |
|---|
| 317 | +{ |
|---|
| 318 | + unsigned long *addr = &sb->map[SB_NR_TO_INDEX(sb, bitnr)].cleared; |
|---|
| 319 | + |
|---|
| 320 | + set_bit(SB_NR_TO_BIT(sb, bitnr), addr); |
|---|
| 321 | +} |
|---|
| 322 | + |
|---|
| 313 | 323 | static inline void sbitmap_clear_bit_unlock(struct sbitmap *sb, |
|---|
| 314 | 324 | unsigned int bitnr) |
|---|
| 315 | 325 | { |
|---|
| .. | .. |
|---|
| 320 | 330 | { |
|---|
| 321 | 331 | return test_bit(SB_NR_TO_BIT(sb, bitnr), __sbitmap_word(sb, bitnr)); |
|---|
| 322 | 332 | } |
|---|
| 323 | | - |
|---|
| 324 | | -unsigned int sbitmap_weight(const struct sbitmap *sb); |
|---|
| 325 | 333 | |
|---|
| 326 | 334 | /** |
|---|
| 327 | 335 | * sbitmap_show() - Dump &struct sbitmap information to a &struct seq_file. |
|---|
| .. | .. |
|---|
| 531 | 539 | */ |
|---|
| 532 | 540 | void sbitmap_queue_show(struct sbitmap_queue *sbq, struct seq_file *m); |
|---|
| 533 | 541 | |
|---|
| 542 | +struct sbq_wait { |
|---|
| 543 | + struct sbitmap_queue *sbq; /* if set, sbq_wait is accounted */ |
|---|
| 544 | + struct wait_queue_entry wait; |
|---|
| 545 | +}; |
|---|
| 546 | + |
|---|
| 547 | +#define DEFINE_SBQ_WAIT(name) \ |
|---|
| 548 | + struct sbq_wait name = { \ |
|---|
| 549 | + .sbq = NULL, \ |
|---|
| 550 | + .wait = { \ |
|---|
| 551 | + .private = current, \ |
|---|
| 552 | + .func = autoremove_wake_function, \ |
|---|
| 553 | + .entry = LIST_HEAD_INIT((name).wait.entry), \ |
|---|
| 554 | + } \ |
|---|
| 555 | + } |
|---|
| 556 | + |
|---|
| 557 | +/* |
|---|
| 558 | + * Wrapper around prepare_to_wait_exclusive(), which maintains some extra |
|---|
| 559 | + * internal state. |
|---|
| 560 | + */ |
|---|
| 561 | +void sbitmap_prepare_to_wait(struct sbitmap_queue *sbq, |
|---|
| 562 | + struct sbq_wait_state *ws, |
|---|
| 563 | + struct sbq_wait *sbq_wait, int state); |
|---|
| 564 | + |
|---|
| 565 | +/* |
|---|
| 566 | + * Must be paired with sbitmap_prepare_to_wait(). |
|---|
| 567 | + */ |
|---|
| 568 | +void sbitmap_finish_wait(struct sbitmap_queue *sbq, struct sbq_wait_state *ws, |
|---|
| 569 | + struct sbq_wait *sbq_wait); |
|---|
| 570 | + |
|---|
| 571 | +/* |
|---|
| 572 | + * Wrapper around add_wait_queue(), which maintains some extra internal state |
|---|
| 573 | + */ |
|---|
| 574 | +void sbitmap_add_wait_queue(struct sbitmap_queue *sbq, |
|---|
| 575 | + struct sbq_wait_state *ws, |
|---|
| 576 | + struct sbq_wait *sbq_wait); |
|---|
| 577 | + |
|---|
| 578 | +/* |
|---|
| 579 | + * Must be paired with sbitmap_add_wait_queue() |
|---|
| 580 | + */ |
|---|
| 581 | +void sbitmap_del_wait_queue(struct sbq_wait *sbq_wait); |
|---|
| 582 | + |
|---|
| 534 | 583 | #endif /* __LINUX_SCALE_BITMAP_H */ |
|---|