1f1b079b4SArtur Paszkiewicz /* SPDX-License-Identifier: BSD-3-Clause
2*a6dbe372Spaul luse * Copyright (C) 2022 Intel Corporation.
3f1b079b4SArtur Paszkiewicz * All rights reserved.
4f1b079b4SArtur Paszkiewicz */
5f1b079b4SArtur Paszkiewicz
6f1b079b4SArtur Paszkiewicz #include "spdk/log.h"
7f1b079b4SArtur Paszkiewicz #include "spdk/util.h"
8f1b079b4SArtur Paszkiewicz
9f1b079b4SArtur Paszkiewicz #include "ftl_bitmap.h"
10f1b079b4SArtur Paszkiewicz #include "ftl_internal.h"
11f1b079b4SArtur Paszkiewicz
12f1b079b4SArtur Paszkiewicz typedef unsigned long bitmap_word;
13f1b079b4SArtur Paszkiewicz
14f1b079b4SArtur Paszkiewicz const size_t ftl_bitmap_buffer_alignment = sizeof(bitmap_word);
15f1b079b4SArtur Paszkiewicz
16f1b079b4SArtur Paszkiewicz #define FTL_BITMAP_WORD_SHIFT spdk_u32log2(sizeof(bitmap_word) * 8)
17f1b079b4SArtur Paszkiewicz #define FTL_BITMAP_WORD_MASK (~(~0UL << FTL_BITMAP_WORD_SHIFT))
18f1b079b4SArtur Paszkiewicz
19f1b079b4SArtur Paszkiewicz uint64_t
ftl_bitmap_bits_to_size(uint64_t bits)20f1b079b4SArtur Paszkiewicz ftl_bitmap_bits_to_size(uint64_t bits)
21f1b079b4SArtur Paszkiewicz {
22f1b079b4SArtur Paszkiewicz uint64_t size;
23f1b079b4SArtur Paszkiewicz
24f1b079b4SArtur Paszkiewicz if (bits < ftl_bitmap_buffer_alignment) {
25f1b079b4SArtur Paszkiewicz bits = ftl_bitmap_buffer_alignment;
26f1b079b4SArtur Paszkiewicz }
27f1b079b4SArtur Paszkiewicz
28f1b079b4SArtur Paszkiewicz size = spdk_divide_round_up(bits, 8);
29f1b079b4SArtur Paszkiewicz size = spdk_divide_round_up(size, ftl_bitmap_buffer_alignment) * ftl_bitmap_buffer_alignment;
30f1b079b4SArtur Paszkiewicz
31f1b079b4SArtur Paszkiewicz return size;
32f1b079b4SArtur Paszkiewicz }
33f1b079b4SArtur Paszkiewicz
34f1b079b4SArtur Paszkiewicz uint64_t
ftl_bitmap_bits_to_blocks(uint64_t bits)35f1b079b4SArtur Paszkiewicz ftl_bitmap_bits_to_blocks(uint64_t bits)
36f1b079b4SArtur Paszkiewicz {
37f1b079b4SArtur Paszkiewicz uint64_t size = ftl_bitmap_bits_to_size(bits);
38f1b079b4SArtur Paszkiewicz
39f1b079b4SArtur Paszkiewicz return spdk_divide_round_up(size, FTL_BLOCK_SIZE);
40f1b079b4SArtur Paszkiewicz }
41f1b079b4SArtur Paszkiewicz
42f1b079b4SArtur Paszkiewicz struct ftl_bitmap {
43f1b079b4SArtur Paszkiewicz bitmap_word *buf;
44f1b079b4SArtur Paszkiewicz size_t size;
45f1b079b4SArtur Paszkiewicz };
46f1b079b4SArtur Paszkiewicz
ftl_bitmap_create(void * buf,size_t size)47f1b079b4SArtur Paszkiewicz struct ftl_bitmap *ftl_bitmap_create(void *buf, size_t size)
48f1b079b4SArtur Paszkiewicz {
49f1b079b4SArtur Paszkiewicz struct ftl_bitmap *bitmap;
50f1b079b4SArtur Paszkiewicz
51f1b079b4SArtur Paszkiewicz if ((uintptr_t)buf % ftl_bitmap_buffer_alignment) {
52f1b079b4SArtur Paszkiewicz SPDK_ERRLOG("Buffer for bitmap must be aligned to %lu bytes\n",
53f1b079b4SArtur Paszkiewicz ftl_bitmap_buffer_alignment);
54f1b079b4SArtur Paszkiewicz return NULL;
55f1b079b4SArtur Paszkiewicz }
56f1b079b4SArtur Paszkiewicz
57f1b079b4SArtur Paszkiewicz if (size % ftl_bitmap_buffer_alignment) {
58f1b079b4SArtur Paszkiewicz SPDK_ERRLOG("Size of buffer for bitmap must be divisible by %lu bytes\n",
59f1b079b4SArtur Paszkiewicz ftl_bitmap_buffer_alignment);
60f1b079b4SArtur Paszkiewicz return NULL;
61f1b079b4SArtur Paszkiewicz }
62f1b079b4SArtur Paszkiewicz
63f1b079b4SArtur Paszkiewicz bitmap = calloc(1, sizeof(*bitmap));
64f1b079b4SArtur Paszkiewicz if (!bitmap) {
65f1b079b4SArtur Paszkiewicz return NULL;
66f1b079b4SArtur Paszkiewicz }
67f1b079b4SArtur Paszkiewicz
68f1b079b4SArtur Paszkiewicz bitmap->buf = buf;
69f1b079b4SArtur Paszkiewicz bitmap->size = size / sizeof(bitmap_word);
70f1b079b4SArtur Paszkiewicz
71f1b079b4SArtur Paszkiewicz return bitmap;
72f1b079b4SArtur Paszkiewicz }
73f1b079b4SArtur Paszkiewicz
74f1b079b4SArtur Paszkiewicz void
ftl_bitmap_destroy(struct ftl_bitmap * bitmap)75f1b079b4SArtur Paszkiewicz ftl_bitmap_destroy(struct ftl_bitmap *bitmap)
76f1b079b4SArtur Paszkiewicz {
77f1b079b4SArtur Paszkiewicz free(bitmap);
78f1b079b4SArtur Paszkiewicz }
79f1b079b4SArtur Paszkiewicz
80f1b079b4SArtur Paszkiewicz static inline void
locate_bit(const struct ftl_bitmap * bitmap,uint64_t bit,bitmap_word ** word_out,uint8_t * word_bit_idx_out)81f1b079b4SArtur Paszkiewicz locate_bit(const struct ftl_bitmap *bitmap, uint64_t bit,
82f1b079b4SArtur Paszkiewicz bitmap_word **word_out, uint8_t *word_bit_idx_out)
83f1b079b4SArtur Paszkiewicz {
84f1b079b4SArtur Paszkiewicz size_t word_idx = bit >> FTL_BITMAP_WORD_SHIFT;
85f1b079b4SArtur Paszkiewicz
86f1b079b4SArtur Paszkiewicz assert(word_idx < bitmap->size);
87f1b079b4SArtur Paszkiewicz
88f1b079b4SArtur Paszkiewicz *word_bit_idx_out = bit & FTL_BITMAP_WORD_MASK;
89f1b079b4SArtur Paszkiewicz *word_out = &bitmap->buf[word_idx];
90f1b079b4SArtur Paszkiewicz }
91f1b079b4SArtur Paszkiewicz
92f1b079b4SArtur Paszkiewicz bool
ftl_bitmap_get(const struct ftl_bitmap * bitmap,uint64_t bit)93f1b079b4SArtur Paszkiewicz ftl_bitmap_get(const struct ftl_bitmap *bitmap, uint64_t bit)
94f1b079b4SArtur Paszkiewicz {
95f1b079b4SArtur Paszkiewicz bitmap_word *word;
96f1b079b4SArtur Paszkiewicz uint8_t word_bit_idx;
97f1b079b4SArtur Paszkiewicz
98f1b079b4SArtur Paszkiewicz locate_bit(bitmap, bit, &word, &word_bit_idx);
99f1b079b4SArtur Paszkiewicz
100f1b079b4SArtur Paszkiewicz return *word & (1UL << word_bit_idx);
101f1b079b4SArtur Paszkiewicz }
102f1b079b4SArtur Paszkiewicz
103f1b079b4SArtur Paszkiewicz void
ftl_bitmap_set(struct ftl_bitmap * bitmap,uint64_t bit)104f1b079b4SArtur Paszkiewicz ftl_bitmap_set(struct ftl_bitmap *bitmap, uint64_t bit)
105f1b079b4SArtur Paszkiewicz {
106f1b079b4SArtur Paszkiewicz bitmap_word *word;
107f1b079b4SArtur Paszkiewicz uint8_t word_bit_idx;
108f1b079b4SArtur Paszkiewicz
109f1b079b4SArtur Paszkiewicz locate_bit(bitmap, bit, &word, &word_bit_idx);
110f1b079b4SArtur Paszkiewicz
111f1b079b4SArtur Paszkiewicz *word |= (1UL << word_bit_idx);
112f1b079b4SArtur Paszkiewicz }
113f1b079b4SArtur Paszkiewicz
114f1b079b4SArtur Paszkiewicz void
ftl_bitmap_clear(struct ftl_bitmap * bitmap,uint64_t bit)115f1b079b4SArtur Paszkiewicz ftl_bitmap_clear(struct ftl_bitmap *bitmap, uint64_t bit)
116f1b079b4SArtur Paszkiewicz {
117f1b079b4SArtur Paszkiewicz bitmap_word *word;
118f1b079b4SArtur Paszkiewicz uint8_t word_bit_idx;
119f1b079b4SArtur Paszkiewicz
120f1b079b4SArtur Paszkiewicz locate_bit(bitmap, bit, &word, &word_bit_idx);
121f1b079b4SArtur Paszkiewicz
122f1b079b4SArtur Paszkiewicz *word &= ~(1UL << word_bit_idx);
123f1b079b4SArtur Paszkiewicz }
124f1b079b4SArtur Paszkiewicz
125f1b079b4SArtur Paszkiewicz static uint64_t
ftl_bitmap_find_first(struct ftl_bitmap * bitmap,uint64_t start_bit,uint64_t end_bit,bool value)126f1b079b4SArtur Paszkiewicz ftl_bitmap_find_first(struct ftl_bitmap *bitmap, uint64_t start_bit,
127f1b079b4SArtur Paszkiewicz uint64_t end_bit, bool value)
128f1b079b4SArtur Paszkiewicz {
129f1b079b4SArtur Paszkiewicz bitmap_word skip = (value ? 0 : ~0UL);
130f1b079b4SArtur Paszkiewicz bitmap_word word;
131f1b079b4SArtur Paszkiewicz size_t i, end;
132f1b079b4SArtur Paszkiewicz uint64_t ret;
133f1b079b4SArtur Paszkiewicz
134f1b079b4SArtur Paszkiewicz assert(start_bit <= end_bit);
135f1b079b4SArtur Paszkiewicz
136f1b079b4SArtur Paszkiewicz i = start_bit >> FTL_BITMAP_WORD_SHIFT;
137f1b079b4SArtur Paszkiewicz assert(i < bitmap->size);
138f1b079b4SArtur Paszkiewicz
139f1b079b4SArtur Paszkiewicz word = (bitmap->buf[i] ^ skip) & (~0UL << (start_bit & FTL_BITMAP_WORD_MASK));
140f1b079b4SArtur Paszkiewicz if (word != 0) {
141f1b079b4SArtur Paszkiewicz goto found;
142f1b079b4SArtur Paszkiewicz }
143f1b079b4SArtur Paszkiewicz
144f1b079b4SArtur Paszkiewicz end = spdk_min((end_bit >> FTL_BITMAP_WORD_SHIFT) + 1, bitmap->size);
145f1b079b4SArtur Paszkiewicz for (i = i + 1; i < end; i++) {
146f1b079b4SArtur Paszkiewicz word = bitmap->buf[i] ^ skip;
147f1b079b4SArtur Paszkiewicz if (word != 0) {
148f1b079b4SArtur Paszkiewicz goto found;
149f1b079b4SArtur Paszkiewicz }
150f1b079b4SArtur Paszkiewicz }
151f1b079b4SArtur Paszkiewicz
152f1b079b4SArtur Paszkiewicz return UINT64_MAX;
153f1b079b4SArtur Paszkiewicz found:
154f1b079b4SArtur Paszkiewicz ret = (i << FTL_BITMAP_WORD_SHIFT) + __builtin_ctzl(word);
155f1b079b4SArtur Paszkiewicz if (ret > end_bit) {
156f1b079b4SArtur Paszkiewicz return UINT64_MAX;
157f1b079b4SArtur Paszkiewicz }
158f1b079b4SArtur Paszkiewicz return ret;
159f1b079b4SArtur Paszkiewicz }
160f1b079b4SArtur Paszkiewicz
161f1b079b4SArtur Paszkiewicz uint64_t
ftl_bitmap_find_first_set(struct ftl_bitmap * bitmap,uint64_t start_bit,uint64_t end_bit)162f1b079b4SArtur Paszkiewicz ftl_bitmap_find_first_set(struct ftl_bitmap *bitmap, uint64_t start_bit, uint64_t end_bit)
163f1b079b4SArtur Paszkiewicz {
164f1b079b4SArtur Paszkiewicz return ftl_bitmap_find_first(bitmap, start_bit, end_bit, true);
165f1b079b4SArtur Paszkiewicz }
166f1b079b4SArtur Paszkiewicz
167f1b079b4SArtur Paszkiewicz uint64_t
ftl_bitmap_find_first_clear(struct ftl_bitmap * bitmap,uint64_t start_bit,uint64_t end_bit)168f1b079b4SArtur Paszkiewicz ftl_bitmap_find_first_clear(struct ftl_bitmap *bitmap, uint64_t start_bit,
169f1b079b4SArtur Paszkiewicz uint64_t end_bit)
170f1b079b4SArtur Paszkiewicz {
171f1b079b4SArtur Paszkiewicz return ftl_bitmap_find_first(bitmap, start_bit, end_bit, false);
172f1b079b4SArtur Paszkiewicz }
173f1b079b4SArtur Paszkiewicz
174f1b079b4SArtur Paszkiewicz uint64_t
ftl_bitmap_count_set(struct ftl_bitmap * bitmap)175f1b079b4SArtur Paszkiewicz ftl_bitmap_count_set(struct ftl_bitmap *bitmap)
176f1b079b4SArtur Paszkiewicz {
177f1b079b4SArtur Paszkiewicz size_t i;
178f1b079b4SArtur Paszkiewicz bitmap_word *word = bitmap->buf;
179f1b079b4SArtur Paszkiewicz uint64_t count = 0;
180f1b079b4SArtur Paszkiewicz
181f1b079b4SArtur Paszkiewicz for (i = 0; i < bitmap->size; i++, word++) {
182f1b079b4SArtur Paszkiewicz count += __builtin_popcountl(*word);
183f1b079b4SArtur Paszkiewicz }
184f1b079b4SArtur Paszkiewicz
185f1b079b4SArtur Paszkiewicz return count;
186f1b079b4SArtur Paszkiewicz }
187