]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - scrub/bitmap.c
aecdba0d93ffaedbd5716a71953680077b2aab7e
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; pos != (l); \
27 pos = n, n = pos ? pos->avl_nextino : NULL)
29 #define avl_for_each_safe(tree, pos, n) \
30 for (pos = (tree)->avl_firstino, n = pos ? pos->avl_nextino : NULL; \
32 pos = n, n = pos ? pos->avl_nextino : NULL)
34 #define avl_for_each(tree, pos) \
35 for (pos = (tree)->avl_firstino; pos != NULL; pos = pos->avl_nextino)
38 struct avl64node btn_node
;
45 struct avl64node
*node
)
47 struct bitmap_node
*btn
;
49 btn
= container_of(node
, struct bitmap_node
, btn_node
);
50 return btn
->btn_start
;
55 struct avl64node
*node
)
57 struct bitmap_node
*btn
;
59 btn
= container_of(node
, struct bitmap_node
, btn_node
);
60 return btn
->btn_start
+ btn
->btn_length
;
63 static struct avl64ops bitmap_ops
= {
68 /* Initialize a bitmap. */
71 struct bitmap
**bmapp
)
75 bmap
= calloc(1, sizeof(struct bitmap
));
78 bmap
->bt_tree
= malloc(sizeof(struct avl64tree_desc
));
84 pthread_mutex_init(&bmap
->bt_lock
, NULL
);
85 avl64_init_tree(bmap
->bt_tree
, &bitmap_ops
);
94 struct bitmap
**bmapp
)
97 struct avl64node
*node
;
99 struct bitmap_node
*ext
;
102 avl_for_each_safe(bmap
->bt_tree
, node
, n
) {
103 ext
= container_of(node
, struct bitmap_node
, btn_node
);
110 /* Create a new bitmap extent node. */
111 static struct bitmap_node
*
116 struct bitmap_node
*ext
;
118 ext
= malloc(sizeof(struct bitmap_node
));
122 ext
->btn_node
.avl_nextino
= NULL
;
123 ext
->btn_start
= start
;
124 ext
->btn_length
= len
;
129 /* Set a region of bits (locked). */
136 struct avl64node
*firstn
;
137 struct avl64node
*lastn
;
138 struct avl64node
*pos
;
141 struct bitmap_node
*ext
;
144 struct avl64node
*node
;
147 /* Find any existing nodes adjacent or within that range. */
148 avl64_findranges(bmap
->bt_tree
, start
- 1, start
+ length
+ 1,
151 /* Nothing, just insert a new extent. */
152 if (firstn
== NULL
&& lastn
== NULL
) {
153 ext
= bitmap_node_init(start
, length
);
157 node
= avl64_insert(bmap
->bt_tree
, &ext
->btn_node
);
167 assert(firstn
!= NULL
&& lastn
!= NULL
);
171 avl_for_each_range_safe(pos
, n
, l
, firstn
, lastn
) {
172 ext
= container_of(pos
, struct bitmap_node
, btn_node
);
174 /* Bail if the new extent is contained within an old one. */
175 if (ext
->btn_start
<= start
&&
176 ext
->btn_start
+ ext
->btn_length
>= start
+ length
)
179 /* Check for overlapping and adjacent extents. */
180 if (ext
->btn_start
+ ext
->btn_length
>= start
||
181 ext
->btn_start
<= start
+ length
) {
182 if (ext
->btn_start
< start
) {
183 new_start
= ext
->btn_start
;
184 new_length
+= ext
->btn_length
;
187 if (ext
->btn_start
+ ext
->btn_length
>
188 new_start
+ new_length
)
189 new_length
= ext
->btn_start
+ ext
->btn_length
-
192 avl64_delete(bmap
->bt_tree
, pos
);
197 ext
= bitmap_node_init(new_start
, new_length
);
201 node
= avl64_insert(bmap
->bt_tree
, &ext
->btn_node
);
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 bool (*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 moveon
= 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");