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