]>
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
)
77 bmap
= calloc(1, sizeof(struct bitmap
));
80 bmap
->bt_tree
= malloc(sizeof(struct avl64tree_desc
));
86 ret
= pthread_mutex_init(&bmap
->bt_lock
, NULL
);
90 avl64_init_tree(bmap
->bt_tree
, &bitmap_ops
);
104 struct bitmap
**bmapp
)
107 struct avl64node
*node
;
109 struct bitmap_node
*ext
;
112 avl_for_each_safe(bmap
->bt_tree
, node
, n
) {
113 ext
= container_of(node
, struct bitmap_node
, btn_node
);
121 /* Create a new bitmap extent node. */
122 static struct bitmap_node
*
127 struct bitmap_node
*ext
;
129 ext
= malloc(sizeof(struct bitmap_node
));
133 ext
->btn_node
.avl_nextino
= NULL
;
134 ext
->btn_start
= start
;
135 ext
->btn_length
= len
;
140 /* Create a new bitmap node and insert it. */
147 struct bitmap_node
*ext
;
148 struct avl64node
*node
;
150 ext
= bitmap_node_init(start
, length
);
154 node
= avl64_insert(bmap
->bt_tree
, &ext
->btn_node
);
163 /* Set a region of bits (locked). */
170 struct avl64node
*firstn
;
171 struct avl64node
*lastn
;
172 struct avl64node
*pos
;
175 struct bitmap_node
*ext
;
179 /* Find any existing nodes adjacent or within that range. */
180 avl64_findranges(bmap
->bt_tree
, start
- 1, start
+ length
+ 1,
183 /* Nothing, just insert a new extent. */
184 if (firstn
== NULL
&& lastn
== NULL
)
185 return __bitmap_insert(bmap
, start
, length
);
187 assert(firstn
!= NULL
&& lastn
!= NULL
);
191 avl_for_each_range_safe(pos
, n
, l
, firstn
, lastn
) {
192 ext
= container_of(pos
, struct bitmap_node
, btn_node
);
194 /* Bail if the new extent is contained within an old one. */
195 if (ext
->btn_start
<= start
&&
196 ext
->btn_start
+ ext
->btn_length
>= start
+ length
)
199 /* Check for overlapping and adjacent extents. */
200 if (ext
->btn_start
+ ext
->btn_length
>= start
||
201 ext
->btn_start
<= start
+ length
) {
202 if (ext
->btn_start
< start
) {
203 new_start
= ext
->btn_start
;
204 new_length
+= ext
->btn_length
;
207 if (ext
->btn_start
+ ext
->btn_length
>
208 new_start
+ new_length
)
209 new_length
= ext
->btn_start
+ ext
->btn_length
-
212 avl64_delete(bmap
->bt_tree
, pos
);
217 return __bitmap_insert(bmap
, new_start
, new_length
);
220 /* Set a region of bits. */
229 pthread_mutex_lock(&bmap
->bt_lock
);
230 res
= __bitmap_set(bmap
, start
, length
);
231 pthread_mutex_unlock(&bmap
->bt_lock
);
236 #if 0 /* Unused, provided for completeness. */
237 /* Clear a region of bits. */
244 struct avl64node
*firstn
;
245 struct avl64node
*lastn
;
246 struct avl64node
*pos
;
249 struct bitmap_node
*ext
;
252 struct avl64node
*node
;
255 pthread_mutex_lock(&bmap
->bt_lock
);
256 /* Find any existing nodes over that range. */
257 avl64_findranges(bmap
->bt_tree
, start
, start
+ len
, &firstn
, &lastn
);
259 /* Nothing, we're done. */
260 if (firstn
== NULL
&& lastn
== NULL
) {
261 pthread_mutex_unlock(&bmap
->bt_lock
);
265 assert(firstn
!= NULL
&& lastn
!= NULL
);
267 /* Delete or truncate everything in sight. */
268 avl_for_each_range_safe(pos
, n
, l
, firstn
, lastn
) {
269 ext
= container_of(pos
, struct bitmap_node
, btn_node
);
272 if (ext
->btn_start
< start
)
274 if (ext
->btn_start
+ ext
->btn_length
> start
+ len
)
278 /* Extent totally within range; delete. */
279 avl64_delete(bmap
->bt_tree
, pos
);
283 /* Extent is left-adjacent; truncate. */
284 ext
->btn_length
= start
- ext
->btn_start
;
287 /* Extent is right-adjacent; move it. */
288 ext
->btn_length
= ext
->btn_start
+ ext
->btn_length
-
290 ext
->btn_start
= start
+ len
;
293 /* Extent overlaps both ends. */
294 ext
->btn_length
= start
- ext
->btn_start
;
295 new_start
= start
+ len
;
296 new_length
= ext
->btn_start
+ ext
->btn_length
-
299 ext
= bitmap_node_init(new_start
, new_length
);
303 node
= avl64_insert(bmap
->bt_tree
, &ext
->btn_node
);
312 pthread_mutex_unlock(&bmap
->bt_lock
);
318 /* Iterate the set regions of this bitmap. */
322 int (*fn
)(uint64_t, uint64_t, void *),
325 struct avl64node
*node
;
326 struct bitmap_node
*ext
;
329 pthread_mutex_lock(&bmap
->bt_lock
);
330 avl_for_each(bmap
->bt_tree
, node
) {
331 ext
= container_of(node
, struct bitmap_node
, btn_node
);
332 error
= fn(ext
->btn_start
, ext
->btn_length
, arg
);
336 pthread_mutex_unlock(&bmap
->bt_lock
);
342 /* Do any bitmap extents overlap the given one? (locked) */
349 struct avl64node
*firstn
;
350 struct avl64node
*lastn
;
352 /* Find any existing nodes over that range. */
353 avl64_findranges(bmap
->bt_tree
, start
, start
+ len
, &firstn
, &lastn
);
355 return firstn
!= NULL
&& lastn
!= NULL
;
358 /* Is any part of this range set? */
367 pthread_mutex_lock(&bmap
->bt_lock
);
368 res
= __bitmap_test(bmap
, start
, len
);
369 pthread_mutex_unlock(&bmap
->bt_lock
);
374 /* Are none of the bits set? */
379 return bmap
->bt_tree
->avl_firstino
== NULL
;
389 printf("%"PRIu64
":%"PRIu64
"\n", startblock
, blockcount
);
398 printf("BITMAP DUMP %p\n", bmap
);
399 bitmap_iterate(bmap
, bitmap_dump_fn
, NULL
);
400 printf("BITMAP DUMP DONE\n");