]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - libfrog/bitmap.c
1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2018 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
11 #include "platform_defs.h"
17 * Space Efficient Bitmap
19 * Implements a space-efficient bitmap. We use an AVL tree to manage
20 * extent records that tell us which ranges are set; the bitmap key is
21 * an arbitrary uint64_t. The usual bitmap operations (set, clear,
22 * test, test and set) are supported, plus we can iterate set ranges.
25 #define avl_for_each_range_safe(pos, n, l, first, last) \
26 for (pos = (first), n = pos->avl_nextino, l = (last)->avl_nextino; \
28 pos = n, n = pos ? pos->avl_nextino : NULL)
30 #define avl_for_each_safe(tree, pos, n) \
31 for (pos = (tree)->avl_firstino, n = pos ? pos->avl_nextino : NULL; \
33 pos = n, n = pos ? pos->avl_nextino : NULL)
35 #define avl_for_each(tree, pos) \
36 for (pos = (tree)->avl_firstino; pos != NULL; pos = pos->avl_nextino)
39 struct avl64node btn_node
;
46 struct avl64node
*node
)
48 struct bitmap_node
*btn
;
50 btn
= container_of(node
, struct bitmap_node
, btn_node
);
51 return btn
->btn_start
;
56 struct avl64node
*node
)
58 struct bitmap_node
*btn
;
60 btn
= container_of(node
, struct bitmap_node
, btn_node
);
61 return btn
->btn_start
+ btn
->btn_length
;
64 static struct avl64ops bitmap_ops
= {
69 /* Initialize a bitmap. */
72 struct bitmap
**bmapp
)
76 bmap
= calloc(1, sizeof(struct bitmap
));
79 bmap
->bt_tree
= malloc(sizeof(struct avl64tree_desc
));
85 pthread_mutex_init(&bmap
->bt_lock
, NULL
);
86 avl64_init_tree(bmap
->bt_tree
, &bitmap_ops
);
95 struct bitmap
**bmapp
)
98 struct avl64node
*node
;
100 struct bitmap_node
*ext
;
103 avl_for_each_safe(bmap
->bt_tree
, node
, n
) {
104 ext
= container_of(node
, struct bitmap_node
, btn_node
);
112 /* Create a new bitmap extent node. */
113 static struct bitmap_node
*
118 struct bitmap_node
*ext
;
120 ext
= malloc(sizeof(struct bitmap_node
));
124 ext
->btn_node
.avl_nextino
= NULL
;
125 ext
->btn_start
= start
;
126 ext
->btn_length
= len
;
131 /* Create a new bitmap node and insert it. */
138 struct bitmap_node
*ext
;
139 struct avl64node
*node
;
141 ext
= bitmap_node_init(start
, length
);
145 node
= avl64_insert(bmap
->bt_tree
, &ext
->btn_node
);
154 /* Set a region of bits (locked). */
161 struct avl64node
*firstn
;
162 struct avl64node
*lastn
;
163 struct avl64node
*pos
;
166 struct bitmap_node
*ext
;
170 /* Find any existing nodes adjacent or within that range. */
171 avl64_findranges(bmap
->bt_tree
, start
- 1, start
+ length
+ 1,
174 /* Nothing, just insert a new extent. */
175 if (firstn
== NULL
&& lastn
== NULL
)
176 return __bitmap_insert(bmap
, start
, length
);
178 assert(firstn
!= NULL
&& lastn
!= NULL
);
182 avl_for_each_range_safe(pos
, n
, l
, firstn
, lastn
) {
183 ext
= container_of(pos
, struct bitmap_node
, btn_node
);
185 /* Bail if the new extent is contained within an old one. */
186 if (ext
->btn_start
<= start
&&
187 ext
->btn_start
+ ext
->btn_length
>= start
+ length
)
190 /* Check for overlapping and adjacent extents. */
191 if (ext
->btn_start
+ ext
->btn_length
>= start
||
192 ext
->btn_start
<= start
+ length
) {
193 if (ext
->btn_start
< start
) {
194 new_start
= ext
->btn_start
;
195 new_length
+= ext
->btn_length
;
198 if (ext
->btn_start
+ ext
->btn_length
>
199 new_start
+ new_length
)
200 new_length
= ext
->btn_start
+ ext
->btn_length
-
203 avl64_delete(bmap
->bt_tree
, pos
);
208 return __bitmap_insert(bmap
, new_start
, new_length
);
211 /* Set a region of bits. */
220 pthread_mutex_lock(&bmap
->bt_lock
);
221 res
= __bitmap_set(bmap
, start
, length
);
222 pthread_mutex_unlock(&bmap
->bt_lock
);
227 #if 0 /* Unused, provided for completeness. */
228 /* Clear a region of bits. */
235 struct avl64node
*firstn
;
236 struct avl64node
*lastn
;
237 struct avl64node
*pos
;
240 struct bitmap_node
*ext
;
243 struct avl64node
*node
;
246 pthread_mutex_lock(&bmap
->bt_lock
);
247 /* Find any existing nodes over that range. */
248 avl64_findranges(bmap
->bt_tree
, start
, start
+ len
, &firstn
, &lastn
);
250 /* Nothing, we're done. */
251 if (firstn
== NULL
&& lastn
== NULL
) {
252 pthread_mutex_unlock(&bmap
->bt_lock
);
256 assert(firstn
!= NULL
&& lastn
!= NULL
);
258 /* Delete or truncate everything in sight. */
259 avl_for_each_range_safe(pos
, n
, l
, firstn
, lastn
) {
260 ext
= container_of(pos
, struct bitmap_node
, btn_node
);
263 if (ext
->btn_start
< start
)
265 if (ext
->btn_start
+ ext
->btn_length
> start
+ len
)
269 /* Extent totally within range; delete. */
270 avl64_delete(bmap
->bt_tree
, pos
);
274 /* Extent is left-adjacent; truncate. */
275 ext
->btn_length
= start
- ext
->btn_start
;
278 /* Extent is right-adjacent; move it. */
279 ext
->btn_length
= ext
->btn_start
+ ext
->btn_length
-
281 ext
->btn_start
= start
+ len
;
284 /* Extent overlaps both ends. */
285 ext
->btn_length
= start
- ext
->btn_start
;
286 new_start
= start
+ len
;
287 new_length
= ext
->btn_start
+ ext
->btn_length
-
290 ext
= bitmap_node_init(new_start
, new_length
);
294 node
= avl64_insert(bmap
->bt_tree
, &ext
->btn_node
);
303 pthread_mutex_unlock(&bmap
->bt_lock
);
309 /* Iterate the set regions of this bitmap. */
313 int (*fn
)(uint64_t, uint64_t, void *),
316 struct avl64node
*node
;
317 struct bitmap_node
*ext
;
320 pthread_mutex_lock(&bmap
->bt_lock
);
321 avl_for_each(bmap
->bt_tree
, node
) {
322 ext
= container_of(node
, struct bitmap_node
, btn_node
);
323 error
= fn(ext
->btn_start
, ext
->btn_length
, arg
);
327 pthread_mutex_unlock(&bmap
->bt_lock
);
333 /* Do any bitmap extents overlap the given one? (locked) */
340 struct avl64node
*firstn
;
341 struct avl64node
*lastn
;
343 /* Find any existing nodes over that range. */
344 avl64_findranges(bmap
->bt_tree
, start
, start
+ len
, &firstn
, &lastn
);
346 return firstn
!= NULL
&& lastn
!= NULL
;
349 /* Is any part of this range set? */
358 pthread_mutex_lock(&bmap
->bt_lock
);
359 res
= __bitmap_test(bmap
, start
, len
);
360 pthread_mutex_unlock(&bmap
->bt_lock
);
365 /* Are none of the bits set? */
370 return bmap
->bt_tree
->avl_firstino
== NULL
;
380 printf("%"PRIu64
":%"PRIu64
"\n", startblock
, blockcount
);
389 printf("BITMAP DUMP %p\n", bmap
);
390 bitmap_iterate(bmap
, bitmap_dump_fn
, NULL
);
391 printf("BITMAP DUMP DONE\n");