/src/e2fsprogs/lib/ext2fs/blkmap64_rb.c
Line | Count | Source |
1 | | /* |
2 | | * blkmap64_rb.c --- Simple rb-tree implementation for bitmaps |
3 | | * |
4 | | * (C)2010 Red Hat, Inc., Lukas Czerner <lczerner@redhat.com> |
5 | | * |
6 | | * %Begin-Header% |
7 | | * This file may be redistributed under the terms of the GNU Public |
8 | | * License. |
9 | | * %End-Header% |
10 | | */ |
11 | | |
12 | | #include "config.h" |
13 | | #include <stdio.h> |
14 | | #include <string.h> |
15 | | #if HAVE_UNISTD_H |
16 | | #include <unistd.h> |
17 | | #endif |
18 | | #include <fcntl.h> |
19 | | #include <time.h> |
20 | | #if HAVE_SYS_STAT_H |
21 | | #include <sys/stat.h> |
22 | | #endif |
23 | | #if HAVE_SYS_TYPES_H |
24 | | #include <sys/types.h> |
25 | | #endif |
26 | | #if HAVE_LINUX_TYPES_H |
27 | | #include <linux/types.h> |
28 | | #endif |
29 | | |
30 | | #include "ext2_fs.h" |
31 | | #include "ext2fsP.h" |
32 | | #include "bmap64.h" |
33 | | #include "rbtree.h" |
34 | | |
35 | | #include <limits.h> |
36 | | |
37 | | struct bmap_rb_extent { |
38 | | struct rb_node node; |
39 | | __u64 start; |
40 | | __u64 count; |
41 | | }; |
42 | | |
43 | | struct ext2fs_rb_private { |
44 | | struct rb_root root; |
45 | | struct bmap_rb_extent *wcursor; |
46 | | struct bmap_rb_extent *rcursor; |
47 | | struct bmap_rb_extent *rcursor_next; |
48 | | #ifdef ENABLE_BMAP_STATS_OPS |
49 | | __u64 mark_hit; |
50 | | __u64 test_hit; |
51 | | #endif |
52 | | }; |
53 | | |
54 | | inline static struct bmap_rb_extent *node_to_extent(struct rb_node *node) |
55 | 0 | { |
56 | | /* |
57 | | * This depends on the fact the struct rb_node is at the |
58 | | * beginning of the bmap_rb_extent structure. We use this |
59 | | * instead of the ext2fs_rb_entry macro because it causes gcc |
60 | | * -Wall to generate a huge amount of noise. |
61 | | */ |
62 | 0 | return (struct bmap_rb_extent *) node; |
63 | 0 | } |
64 | | |
65 | | static int rb_insert_extent(__u64 start, __u64 count, |
66 | | struct ext2fs_rb_private *); |
67 | | static void rb_get_new_extent(struct bmap_rb_extent **, __u64, __u64); |
68 | | |
69 | | /* #define DEBUG_RB */ |
70 | | |
71 | | #ifdef DEBUG_RB |
72 | | static void print_tree(struct rb_root *root) |
73 | | { |
74 | | struct rb_node *node = NULL; |
75 | | struct bmap_rb_extent *ext; |
76 | | |
77 | | fprintf(stderr, "\t\t\t=================================\n"); |
78 | | node = ext2fs_rb_first(root); |
79 | | for (node = ext2fs_rb_first(root); node != NULL; |
80 | | node = ext2fs_rb_next(node)) { |
81 | | ext = node_to_extent(node); |
82 | | fprintf(stderr, "\t\t\t--> (%llu -> %llu)\n", |
83 | | (unsigned long long) ext->start, |
84 | | (unsigned long long) ext->start + ext->count); |
85 | | } |
86 | | fprintf(stderr, "\t\t\t=================================\n"); |
87 | | } |
88 | | |
89 | | static void check_tree(struct rb_root *root, const char *msg) |
90 | | { |
91 | | struct rb_node *node; |
92 | | struct bmap_rb_extent *ext, *old = NULL; |
93 | | |
94 | | for (node = ext2fs_rb_first(root); node; |
95 | | node = ext2fs_rb_next(node)) { |
96 | | ext = node_to_extent(node); |
97 | | if (ext->count == 0) { |
98 | | fprintf(stderr, "Tree Error: count is zero\n"); |
99 | | fprintf(stderr, "extent: %llu -> %llu (%llu)\n", |
100 | | (unsigned long long) ext->start, |
101 | | (unsigned long long) ext->start + ext->count, |
102 | | (unsigned long long) ext->count); |
103 | | goto err_out; |
104 | | } |
105 | | if (ext->start + ext->count < ext->start) { |
106 | | fprintf(stderr, |
107 | | "Tree Error: start or count is crazy\n"); |
108 | | fprintf(stderr, "extent: %llu -> %llu (%llu)\n", |
109 | | (unsigned long long) ext->start, |
110 | | (unsigned long long) ext->start + ext->count, |
111 | | (unsigned long long) ext->count); |
112 | | goto err_out; |
113 | | } |
114 | | |
115 | | if (old) { |
116 | | if (old->start > ext->start) { |
117 | | fprintf(stderr, "Tree Error: start is crazy\n"); |
118 | | fprintf(stderr, "extent: %llu -> %llu (%llu)\n", |
119 | | (unsigned long long) old->start, |
120 | | (unsigned long long) old->start + old->count, |
121 | | (unsigned long long) old->count); |
122 | | fprintf(stderr, |
123 | | "extent next: %llu -> %llu (%llu)\n", |
124 | | (unsigned long long) ext->start, |
125 | | (unsigned long long) ext->start + ext->count, |
126 | | (unsigned long long) ext->count); |
127 | | goto err_out; |
128 | | } |
129 | | if ((old->start + old->count) >= ext->start) { |
130 | | fprintf(stderr, |
131 | | "Tree Error: extent is crazy\n"); |
132 | | fprintf(stderr, "extent: %llu -> %llu (%llu)\n", |
133 | | (unsigned long long) old->start, |
134 | | (unsigned long long) old->start + old->count, |
135 | | (unsigned long long) old->count); |
136 | | fprintf(stderr, |
137 | | "extent next: %llu -> %llu (%llu)\n", |
138 | | (unsigned long long) ext->start, |
139 | | (unsigned long long) ext->start + ext->count, |
140 | | (unsigned long long) ext->count); |
141 | | goto err_out; |
142 | | } |
143 | | } |
144 | | old = ext; |
145 | | } |
146 | | return; |
147 | | |
148 | | err_out: |
149 | | fprintf(stderr, "%s\n", msg); |
150 | | print_tree(root); |
151 | | exit(1); |
152 | | } |
153 | | #else |
154 | 0 | #define check_tree(root, msg) do {} while (0) |
155 | | #define print_tree(root) do {} while (0) |
156 | | #endif |
157 | | |
158 | | static void rb_get_new_extent(struct bmap_rb_extent **ext, __u64 start, |
159 | | __u64 count) |
160 | 0 | { |
161 | 0 | struct bmap_rb_extent *new_ext; |
162 | 0 | int retval; |
163 | |
|
164 | 0 | retval = ext2fs_get_mem(sizeof (struct bmap_rb_extent), |
165 | 0 | &new_ext); |
166 | 0 | if (retval) |
167 | 0 | abort(); |
168 | | |
169 | 0 | new_ext->start = start; |
170 | 0 | new_ext->count = count; |
171 | 0 | *ext = new_ext; |
172 | 0 | } |
173 | | |
174 | | inline |
175 | | static void rb_free_extent(struct ext2fs_rb_private *bp, |
176 | | struct bmap_rb_extent *ext) |
177 | 0 | { |
178 | 0 | if (bp->wcursor == ext) |
179 | 0 | bp->wcursor = NULL; |
180 | 0 | if (bp->rcursor == ext) |
181 | 0 | bp->rcursor = NULL; |
182 | 0 | if (bp->rcursor_next == ext) |
183 | 0 | bp->rcursor_next = NULL; |
184 | 0 | ext2fs_free_mem(&ext); |
185 | 0 | } |
186 | | |
187 | | static errcode_t rb_alloc_private_data (ext2fs_generic_bitmap_64 bitmap) |
188 | 0 | { |
189 | 0 | struct ext2fs_rb_private *bp; |
190 | 0 | errcode_t retval; |
191 | |
|
192 | 0 | retval = ext2fs_get_mem(sizeof (struct ext2fs_rb_private), &bp); |
193 | 0 | if (retval) |
194 | 0 | return retval; |
195 | | |
196 | 0 | bp->root = RB_ROOT; |
197 | 0 | bp->rcursor = NULL; |
198 | 0 | bp->rcursor_next = NULL; |
199 | 0 | bp->wcursor = NULL; |
200 | |
|
201 | | #ifdef ENABLE_BMAP_STATS_OPS |
202 | | bp->test_hit = 0; |
203 | | bp->mark_hit = 0; |
204 | | #endif |
205 | |
|
206 | 0 | bitmap->private = (void *) bp; |
207 | 0 | return 0; |
208 | 0 | } |
209 | | |
210 | | static errcode_t rb_new_bmap(ext2_filsys fs EXT2FS_ATTR((unused)), |
211 | | ext2fs_generic_bitmap_64 bitmap) |
212 | 0 | { |
213 | 0 | errcode_t retval; |
214 | |
|
215 | 0 | retval = rb_alloc_private_data (bitmap); |
216 | 0 | if (retval) |
217 | 0 | return retval; |
218 | | |
219 | 0 | return 0; |
220 | 0 | } |
221 | | |
222 | | static void rb_free_tree(struct rb_root *root) |
223 | 0 | { |
224 | 0 | struct bmap_rb_extent *ext; |
225 | 0 | struct rb_node *node, *next; |
226 | |
|
227 | 0 | for (node = ext2fs_rb_first(root); node; node = next) { |
228 | 0 | next = ext2fs_rb_next(node); |
229 | 0 | ext = node_to_extent(node); |
230 | 0 | ext2fs_rb_erase(node, root); |
231 | 0 | ext2fs_free_mem(&ext); |
232 | 0 | } |
233 | 0 | } |
234 | | |
235 | | static void rb_free_bmap(ext2fs_generic_bitmap_64 bitmap) |
236 | 0 | { |
237 | 0 | struct ext2fs_rb_private *bp; |
238 | |
|
239 | 0 | bp = (struct ext2fs_rb_private *) bitmap->private; |
240 | |
|
241 | 0 | rb_free_tree(&bp->root); |
242 | 0 | ext2fs_free_mem(&bp); |
243 | 0 | bp = 0; |
244 | 0 | } |
245 | | |
246 | | static errcode_t rb_copy_bmap(ext2fs_generic_bitmap_64 src, |
247 | | ext2fs_generic_bitmap_64 dest) |
248 | 0 | { |
249 | 0 | struct ext2fs_rb_private *src_bp, *dest_bp; |
250 | 0 | struct bmap_rb_extent *src_ext, *dest_ext; |
251 | 0 | struct rb_node *dest_node, *src_node, *dest_last, **n; |
252 | 0 | errcode_t retval = 0; |
253 | |
|
254 | 0 | retval = rb_alloc_private_data (dest); |
255 | 0 | if (retval) |
256 | 0 | return retval; |
257 | | |
258 | 0 | src_bp = (struct ext2fs_rb_private *) src->private; |
259 | 0 | dest_bp = (struct ext2fs_rb_private *) dest->private; |
260 | 0 | src_bp->rcursor = NULL; |
261 | 0 | dest_bp->rcursor = NULL; |
262 | |
|
263 | 0 | src_node = ext2fs_rb_first(&src_bp->root); |
264 | 0 | while (src_node) { |
265 | 0 | src_ext = node_to_extent(src_node); |
266 | 0 | retval = ext2fs_get_mem(sizeof (struct bmap_rb_extent), |
267 | 0 | &dest_ext); |
268 | 0 | if (retval) |
269 | 0 | break; |
270 | | |
271 | 0 | memcpy(dest_ext, src_ext, sizeof(struct bmap_rb_extent)); |
272 | |
|
273 | 0 | dest_node = &dest_ext->node; |
274 | 0 | n = &dest_bp->root.rb_node; |
275 | |
|
276 | 0 | dest_last = NULL; |
277 | 0 | if (*n) { |
278 | 0 | dest_last = ext2fs_rb_last(&dest_bp->root); |
279 | 0 | n = &(dest_last)->rb_right; |
280 | 0 | } |
281 | |
|
282 | 0 | ext2fs_rb_link_node(dest_node, dest_last, n); |
283 | 0 | ext2fs_rb_insert_color(dest_node, &dest_bp->root); |
284 | |
|
285 | 0 | src_node = ext2fs_rb_next(src_node); |
286 | 0 | } |
287 | |
|
288 | 0 | return retval; |
289 | 0 | } |
290 | | |
291 | | static void rb_truncate(__u64 new_max, struct rb_root *root) |
292 | 0 | { |
293 | 0 | struct bmap_rb_extent *ext; |
294 | 0 | struct rb_node *node; |
295 | |
|
296 | 0 | node = ext2fs_rb_last(root); |
297 | 0 | while (node) { |
298 | 0 | ext = node_to_extent(node); |
299 | |
|
300 | 0 | if ((ext->start + ext->count - 1) <= new_max) |
301 | 0 | break; |
302 | 0 | else if (ext->start > new_max) { |
303 | 0 | ext2fs_rb_erase(node, root); |
304 | 0 | ext2fs_free_mem(&ext); |
305 | 0 | node = ext2fs_rb_last(root); |
306 | 0 | continue; |
307 | 0 | } else |
308 | 0 | ext->count = new_max - ext->start + 1; |
309 | 0 | } |
310 | 0 | } |
311 | | |
312 | | static errcode_t rb_resize_bmap(ext2fs_generic_bitmap_64 bmap, |
313 | | __u64 new_end, __u64 new_real_end) |
314 | 0 | { |
315 | 0 | struct ext2fs_rb_private *bp; |
316 | |
|
317 | 0 | bp = (struct ext2fs_rb_private *) bmap->private; |
318 | 0 | bp->rcursor = NULL; |
319 | 0 | bp->wcursor = NULL; |
320 | |
|
321 | 0 | rb_truncate(((new_end < bmap->end) ? new_end : bmap->end) - bmap->start, |
322 | 0 | &bp->root); |
323 | |
|
324 | 0 | bmap->end = new_end; |
325 | 0 | bmap->real_end = new_real_end; |
326 | |
|
327 | 0 | if (bmap->end < bmap->real_end) |
328 | 0 | rb_insert_extent(bmap->end + 1 - bmap->start, |
329 | 0 | bmap->real_end - bmap->end, bp); |
330 | 0 | return 0; |
331 | |
|
332 | 0 | } |
333 | | |
334 | | inline static int |
335 | | rb_test_bit(struct ext2fs_rb_private *bp, __u64 bit) |
336 | 0 | { |
337 | 0 | struct bmap_rb_extent *rcursor, *next_ext = NULL; |
338 | 0 | struct rb_node *parent = NULL, *next; |
339 | 0 | struct rb_node **n = &bp->root.rb_node; |
340 | 0 | struct bmap_rb_extent *ext; |
341 | |
|
342 | 0 | rcursor = bp->rcursor; |
343 | 0 | if (!rcursor) |
344 | 0 | goto search_tree; |
345 | | |
346 | 0 | if (bit >= rcursor->start && bit < rcursor->start + rcursor->count) { |
347 | | #ifdef ENABLE_BMAP_STATS_OPS |
348 | | bp->test_hit++; |
349 | | #endif |
350 | 0 | return 1; |
351 | 0 | } |
352 | | |
353 | 0 | next_ext = bp->rcursor_next; |
354 | 0 | if (!next_ext) { |
355 | 0 | next = ext2fs_rb_next(&rcursor->node); |
356 | 0 | if (next) |
357 | 0 | next_ext = node_to_extent(next); |
358 | 0 | bp->rcursor_next = next_ext; |
359 | 0 | } |
360 | 0 | if (next_ext) { |
361 | 0 | if ((bit >= rcursor->start + rcursor->count) && |
362 | 0 | (bit < next_ext->start)) { |
363 | | #ifdef BMAP_STATS_OPS |
364 | | bp->test_hit++; |
365 | | #endif |
366 | 0 | return 0; |
367 | 0 | } |
368 | 0 | } |
369 | 0 | bp->rcursor = NULL; |
370 | 0 | bp->rcursor_next = NULL; |
371 | |
|
372 | 0 | rcursor = bp->wcursor; |
373 | 0 | if (!rcursor) |
374 | 0 | goto search_tree; |
375 | | |
376 | 0 | if (bit >= rcursor->start && bit < rcursor->start + rcursor->count) |
377 | 0 | return 1; |
378 | | |
379 | 0 | search_tree: |
380 | |
|
381 | 0 | while (*n) { |
382 | 0 | parent = *n; |
383 | 0 | ext = node_to_extent(parent); |
384 | 0 | if (bit < ext->start) |
385 | 0 | n = &(*n)->rb_left; |
386 | 0 | else if (bit >= (ext->start + ext->count)) |
387 | 0 | n = &(*n)->rb_right; |
388 | 0 | else { |
389 | 0 | bp->rcursor = ext; |
390 | 0 | bp->rcursor_next = NULL; |
391 | 0 | return 1; |
392 | 0 | } |
393 | 0 | } |
394 | 0 | return 0; |
395 | 0 | } |
396 | | |
397 | | static int rb_insert_extent(__u64 start, __u64 count, |
398 | | struct ext2fs_rb_private *bp) |
399 | 0 | { |
400 | 0 | struct rb_root *root = &bp->root; |
401 | 0 | struct rb_node *parent = NULL, **n = &root->rb_node; |
402 | 0 | struct rb_node *new_node, *node, *next; |
403 | 0 | struct bmap_rb_extent *new_ext; |
404 | 0 | struct bmap_rb_extent *ext; |
405 | 0 | int retval = 0; |
406 | |
|
407 | 0 | if (count == 0) |
408 | 0 | return 0; |
409 | | |
410 | 0 | bp->rcursor_next = NULL; |
411 | 0 | ext = bp->wcursor; |
412 | 0 | if (ext) { |
413 | 0 | if (start >= ext->start && |
414 | 0 | start <= (ext->start + ext->count)) { |
415 | | #ifdef ENABLE_BMAP_STATS_OPS |
416 | | bp->mark_hit++; |
417 | | #endif |
418 | 0 | goto got_extent; |
419 | 0 | } |
420 | 0 | } |
421 | | |
422 | 0 | while (*n) { |
423 | 0 | parent = *n; |
424 | 0 | ext = node_to_extent(parent); |
425 | |
|
426 | 0 | if (start < ext->start) { |
427 | 0 | n = &(*n)->rb_left; |
428 | 0 | } else if (start > (ext->start + ext->count)) { |
429 | 0 | n = &(*n)->rb_right; |
430 | 0 | } else { |
431 | 0 | got_extent: |
432 | 0 | if ((start + count) <= (ext->start + ext->count)) |
433 | 0 | return 1; |
434 | | |
435 | 0 | if ((ext->start + ext->count) == start) |
436 | 0 | retval = 0; |
437 | 0 | else |
438 | 0 | retval = 1; |
439 | |
|
440 | 0 | count += (start - ext->start); |
441 | 0 | start = ext->start; |
442 | 0 | new_ext = ext; |
443 | 0 | new_node = &ext->node; |
444 | |
|
445 | 0 | goto skip_insert; |
446 | 0 | } |
447 | 0 | } |
448 | | |
449 | 0 | rb_get_new_extent(&new_ext, start, count); |
450 | |
|
451 | 0 | new_node = &new_ext->node; |
452 | 0 | ext2fs_rb_link_node(new_node, parent, n); |
453 | 0 | ext2fs_rb_insert_color(new_node, root); |
454 | 0 | bp->wcursor = new_ext; |
455 | |
|
456 | 0 | node = ext2fs_rb_prev(new_node); |
457 | 0 | if (node) { |
458 | 0 | ext = node_to_extent(node); |
459 | 0 | if ((ext->start + ext->count) == start) { |
460 | 0 | start = ext->start; |
461 | 0 | count += ext->count; |
462 | 0 | ext2fs_rb_erase(node, root); |
463 | 0 | rb_free_extent(bp, ext); |
464 | 0 | } |
465 | 0 | } |
466 | |
|
467 | 0 | skip_insert: |
468 | | /* See if we can merge extent to the right */ |
469 | 0 | for (node = ext2fs_rb_next(new_node); node != NULL; node = next) { |
470 | 0 | next = ext2fs_rb_next(node); |
471 | 0 | ext = node_to_extent(node); |
472 | |
|
473 | 0 | if ((ext->start + ext->count) <= start) |
474 | 0 | continue; |
475 | | |
476 | | /* No more merging */ |
477 | 0 | if ((start + count) < ext->start) |
478 | 0 | break; |
479 | | |
480 | | /* ext is embedded in new_ext interval */ |
481 | 0 | if ((start + count) >= (ext->start + ext->count)) { |
482 | 0 | ext2fs_rb_erase(node, root); |
483 | 0 | rb_free_extent(bp, ext); |
484 | 0 | continue; |
485 | 0 | } else { |
486 | | /* merge ext with new_ext */ |
487 | 0 | count += ((ext->start + ext->count) - |
488 | 0 | (start + count)); |
489 | 0 | ext2fs_rb_erase(node, root); |
490 | 0 | rb_free_extent(bp, ext); |
491 | 0 | break; |
492 | 0 | } |
493 | 0 | } |
494 | |
|
495 | 0 | new_ext->start = start; |
496 | 0 | new_ext->count = count; |
497 | |
|
498 | 0 | return retval; |
499 | 0 | } |
500 | | |
501 | | static int rb_remove_extent(__u64 start, __u64 count, |
502 | | struct ext2fs_rb_private *bp) |
503 | 0 | { |
504 | 0 | struct rb_root *root = &bp->root; |
505 | 0 | struct rb_node *parent = NULL, **n = &root->rb_node; |
506 | 0 | struct rb_node *node; |
507 | 0 | struct bmap_rb_extent *ext; |
508 | 0 | __u64 new_start, new_count; |
509 | 0 | int retval = 0; |
510 | |
|
511 | 0 | if (ext2fs_rb_empty_root(root)) |
512 | 0 | return 0; |
513 | | |
514 | 0 | while (*n) { |
515 | 0 | parent = *n; |
516 | 0 | ext = node_to_extent(parent); |
517 | 0 | if (start < ext->start) { |
518 | 0 | n = &(*n)->rb_left; |
519 | 0 | continue; |
520 | 0 | } else if (start >= (ext->start + ext->count)) { |
521 | 0 | n = &(*n)->rb_right; |
522 | 0 | continue; |
523 | 0 | } |
524 | | |
525 | 0 | if ((start > ext->start) && |
526 | 0 | (start + count) < (ext->start + ext->count)) { |
527 | | /* We have to split extent into two */ |
528 | 0 | new_start = start + count; |
529 | 0 | new_count = (ext->start + ext->count) - new_start; |
530 | |
|
531 | 0 | ext->count = start - ext->start; |
532 | |
|
533 | 0 | rb_insert_extent(new_start, new_count, bp); |
534 | 0 | return 1; |
535 | 0 | } |
536 | | |
537 | 0 | if ((start + count) >= (ext->start + ext->count)) { |
538 | 0 | ext->count = start - ext->start; |
539 | 0 | retval = 1; |
540 | 0 | } |
541 | |
|
542 | 0 | if (0 == ext->count) { |
543 | 0 | parent = ext2fs_rb_next(&ext->node); |
544 | 0 | ext2fs_rb_erase(&ext->node, root); |
545 | 0 | rb_free_extent(bp, ext); |
546 | 0 | break; |
547 | 0 | } |
548 | | |
549 | 0 | if (start == ext->start) { |
550 | 0 | ext->start += count; |
551 | 0 | ext->count -= count; |
552 | 0 | return 1; |
553 | 0 | } |
554 | 0 | } |
555 | | |
556 | | /* See if we should delete or truncate extent on the right */ |
557 | 0 | for (; parent != NULL; parent = node) { |
558 | 0 | node = ext2fs_rb_next(parent); |
559 | 0 | ext = node_to_extent(parent); |
560 | 0 | if ((ext->start + ext->count) <= start) |
561 | 0 | continue; |
562 | | |
563 | | /* No more extents to be removed/truncated */ |
564 | 0 | if ((start + count) < ext->start) |
565 | 0 | break; |
566 | | |
567 | | /* The entire extent is within the region to be removed */ |
568 | 0 | if ((start + count) >= (ext->start + ext->count)) { |
569 | 0 | ext2fs_rb_erase(parent, root); |
570 | 0 | rb_free_extent(bp, ext); |
571 | 0 | retval = 1; |
572 | 0 | continue; |
573 | 0 | } else { |
574 | | /* modify the last extent in region to be removed */ |
575 | 0 | ext->count -= ((start + count) - ext->start); |
576 | 0 | ext->start = start + count; |
577 | 0 | retval = 1; |
578 | 0 | break; |
579 | 0 | } |
580 | 0 | } |
581 | |
|
582 | 0 | return retval; |
583 | 0 | } |
584 | | |
585 | | static int rb_mark_bmap(ext2fs_generic_bitmap_64 bitmap, __u64 arg) |
586 | 0 | { |
587 | 0 | struct ext2fs_rb_private *bp; |
588 | 0 | int retval; |
589 | |
|
590 | 0 | bp = (struct ext2fs_rb_private *) bitmap->private; |
591 | 0 | arg -= bitmap->start; |
592 | |
|
593 | 0 | retval = rb_insert_extent(arg, 1, bp); |
594 | 0 | check_tree(&bp->root, __func__); |
595 | 0 | return retval; |
596 | 0 | } |
597 | | |
598 | | static int rb_unmark_bmap(ext2fs_generic_bitmap_64 bitmap, __u64 arg) |
599 | 0 | { |
600 | 0 | struct ext2fs_rb_private *bp; |
601 | 0 | int retval; |
602 | |
|
603 | 0 | bp = (struct ext2fs_rb_private *) bitmap->private; |
604 | 0 | arg -= bitmap->start; |
605 | |
|
606 | 0 | retval = rb_remove_extent(arg, 1, bp); |
607 | 0 | check_tree(&bp->root, __func__); |
608 | |
|
609 | 0 | return retval; |
610 | 0 | } |
611 | | |
612 | | inline |
613 | | static int rb_test_bmap(ext2fs_generic_bitmap_64 bitmap, __u64 arg) |
614 | 0 | { |
615 | 0 | struct ext2fs_rb_private *bp; |
616 | |
|
617 | 0 | bp = (struct ext2fs_rb_private *) bitmap->private; |
618 | 0 | arg -= bitmap->start; |
619 | |
|
620 | 0 | return rb_test_bit(bp, arg); |
621 | 0 | } |
622 | | |
623 | | static void rb_mark_bmap_extent(ext2fs_generic_bitmap_64 bitmap, __u64 arg, |
624 | | unsigned int num) |
625 | 0 | { |
626 | 0 | struct ext2fs_rb_private *bp; |
627 | |
|
628 | 0 | bp = (struct ext2fs_rb_private *) bitmap->private; |
629 | 0 | arg -= bitmap->start; |
630 | |
|
631 | 0 | rb_insert_extent(arg, num, bp); |
632 | 0 | check_tree(&bp->root, __func__); |
633 | 0 | } |
634 | | |
635 | | static void rb_unmark_bmap_extent(ext2fs_generic_bitmap_64 bitmap, __u64 arg, |
636 | | unsigned int num) |
637 | 0 | { |
638 | 0 | struct ext2fs_rb_private *bp; |
639 | |
|
640 | 0 | bp = (struct ext2fs_rb_private *) bitmap->private; |
641 | 0 | arg -= bitmap->start; |
642 | |
|
643 | 0 | rb_remove_extent(arg, num, bp); |
644 | 0 | check_tree(&bp->root, __func__); |
645 | 0 | } |
646 | | |
647 | | static int rb_test_clear_bmap_extent(ext2fs_generic_bitmap_64 bitmap, |
648 | | __u64 start, unsigned int len) |
649 | 0 | { |
650 | 0 | struct rb_node *parent = NULL, **n; |
651 | 0 | struct rb_node *node, *next; |
652 | 0 | struct ext2fs_rb_private *bp; |
653 | 0 | struct bmap_rb_extent *ext; |
654 | 0 | int retval = 1; |
655 | |
|
656 | 0 | bp = (struct ext2fs_rb_private *) bitmap->private; |
657 | 0 | n = &bp->root.rb_node; |
658 | 0 | start -= bitmap->start; |
659 | |
|
660 | 0 | if (len == 0 || ext2fs_rb_empty_root(&bp->root)) |
661 | 0 | return 1; |
662 | | |
663 | | /* |
664 | | * If we find nothing, we should examine whole extent, but |
665 | | * when we find match, the extent is not clean, thus be return |
666 | | * false. |
667 | | */ |
668 | 0 | while (*n) { |
669 | 0 | parent = *n; |
670 | 0 | ext = node_to_extent(parent); |
671 | 0 | if (start < ext->start) { |
672 | 0 | n = &(*n)->rb_left; |
673 | 0 | } else if (start >= (ext->start + ext->count)) { |
674 | 0 | n = &(*n)->rb_right; |
675 | 0 | } else { |
676 | | /* |
677 | | * We found extent int the tree -> extent is not |
678 | | * clean |
679 | | */ |
680 | 0 | return 0; |
681 | 0 | } |
682 | 0 | } |
683 | | |
684 | 0 | node = parent; |
685 | 0 | while (node) { |
686 | 0 | next = ext2fs_rb_next(node); |
687 | 0 | ext = node_to_extent(node); |
688 | 0 | node = next; |
689 | |
|
690 | 0 | if ((ext->start + ext->count) <= start) |
691 | 0 | continue; |
692 | | |
693 | | /* No more merging */ |
694 | 0 | if ((start + len) <= ext->start) |
695 | 0 | break; |
696 | | |
697 | 0 | retval = 0; |
698 | 0 | break; |
699 | 0 | } |
700 | 0 | return retval; |
701 | 0 | } |
702 | | |
703 | | static errcode_t rb_set_bmap_range(ext2fs_generic_bitmap_64 bitmap, |
704 | | __u64 start, size_t num, void *in) |
705 | 0 | { |
706 | 0 | struct ext2fs_rb_private *bp; |
707 | 0 | unsigned char *cp = in; |
708 | 0 | size_t i; |
709 | 0 | int first_set = -1; |
710 | |
|
711 | 0 | bp = (struct ext2fs_rb_private *) bitmap->private; |
712 | |
|
713 | 0 | for (i = 0; i < num; i++) { |
714 | 0 | if ((i & 7) == 0) { |
715 | 0 | unsigned char c = cp[i/8]; |
716 | 0 | if (c == 0xFF) { |
717 | 0 | if (first_set == -1) |
718 | 0 | first_set = i; |
719 | 0 | i += 7; |
720 | 0 | continue; |
721 | 0 | } |
722 | 0 | if ((c == 0x00) && (first_set == -1)) { |
723 | 0 | i += 7; |
724 | 0 | continue; |
725 | 0 | } |
726 | 0 | } |
727 | 0 | if (ext2fs_test_bit(i, in)) { |
728 | 0 | if (first_set == -1) |
729 | 0 | first_set = i; |
730 | 0 | continue; |
731 | 0 | } |
732 | 0 | if (first_set == -1) |
733 | 0 | continue; |
734 | | |
735 | 0 | rb_insert_extent(start + first_set - bitmap->start, |
736 | 0 | i - first_set, bp); |
737 | 0 | check_tree(&bp->root, __func__); |
738 | 0 | first_set = -1; |
739 | 0 | } |
740 | 0 | if (first_set != -1) { |
741 | 0 | rb_insert_extent(start + first_set - bitmap->start, |
742 | 0 | num - first_set, bp); |
743 | 0 | check_tree(&bp->root, __func__); |
744 | 0 | } |
745 | |
|
746 | 0 | return 0; |
747 | 0 | } |
748 | | |
749 | | static errcode_t rb_get_bmap_range(ext2fs_generic_bitmap_64 bitmap, |
750 | | __u64 start, size_t num, void *out) |
751 | 0 | { |
752 | |
|
753 | 0 | struct rb_node *parent = NULL, *next, **n; |
754 | 0 | struct ext2fs_rb_private *bp; |
755 | 0 | struct bmap_rb_extent *ext; |
756 | 0 | __u64 count, pos; |
757 | |
|
758 | 0 | bp = (struct ext2fs_rb_private *) bitmap->private; |
759 | 0 | n = &bp->root.rb_node; |
760 | 0 | start -= bitmap->start; |
761 | |
|
762 | 0 | if (ext2fs_rb_empty_root(&bp->root)) |
763 | 0 | return 0; |
764 | | |
765 | 0 | while (*n) { |
766 | 0 | parent = *n; |
767 | 0 | ext = node_to_extent(parent); |
768 | 0 | if (start < ext->start) { |
769 | 0 | n = &(*n)->rb_left; |
770 | 0 | } else if (start >= (ext->start + ext->count)) { |
771 | 0 | n = &(*n)->rb_right; |
772 | 0 | } else |
773 | 0 | break; |
774 | 0 | } |
775 | |
|
776 | 0 | memset(out, 0, (num + 7) >> 3); |
777 | |
|
778 | 0 | for (; parent != NULL; parent = next) { |
779 | 0 | next = ext2fs_rb_next(parent); |
780 | 0 | ext = node_to_extent(parent); |
781 | |
|
782 | 0 | pos = ext->start; |
783 | 0 | count = ext->count; |
784 | 0 | if (pos >= start + num) |
785 | 0 | break; |
786 | 0 | if (pos < start) { |
787 | 0 | if (pos + count < start) |
788 | 0 | continue; |
789 | 0 | count -= start - pos; |
790 | 0 | pos = start; |
791 | 0 | } |
792 | 0 | if (pos + count > start + num) |
793 | 0 | count = start + num - pos; |
794 | |
|
795 | 0 | while (count > 0) { |
796 | 0 | if ((count >= 8) && |
797 | 0 | ((pos - start) % 8) == 0) { |
798 | 0 | int nbytes = count >> 3; |
799 | 0 | int offset = (pos - start) >> 3; |
800 | |
|
801 | 0 | memset(((char *) out) + offset, 0xFF, nbytes); |
802 | 0 | pos += nbytes << 3; |
803 | 0 | count -= nbytes << 3; |
804 | 0 | continue; |
805 | 0 | } |
806 | 0 | ext2fs_fast_set_bit64((pos - start), out); |
807 | 0 | pos++; |
808 | 0 | count--; |
809 | 0 | } |
810 | 0 | } |
811 | 0 | return 0; |
812 | 0 | } |
813 | | |
814 | | static void rb_clear_bmap(ext2fs_generic_bitmap_64 bitmap) |
815 | 0 | { |
816 | 0 | struct ext2fs_rb_private *bp; |
817 | |
|
818 | 0 | bp = (struct ext2fs_rb_private *) bitmap->private; |
819 | |
|
820 | 0 | rb_free_tree(&bp->root); |
821 | 0 | bp->rcursor = NULL; |
822 | 0 | bp->rcursor_next = NULL; |
823 | 0 | bp->wcursor = NULL; |
824 | 0 | check_tree(&bp->root, __func__); |
825 | 0 | } |
826 | | |
827 | | static errcode_t rb_find_first_zero(ext2fs_generic_bitmap_64 bitmap, |
828 | | __u64 start, __u64 end, __u64 *out) |
829 | 0 | { |
830 | 0 | struct rb_node *parent = NULL, **n; |
831 | 0 | struct ext2fs_rb_private *bp; |
832 | 0 | struct bmap_rb_extent *ext; |
833 | |
|
834 | 0 | bp = (struct ext2fs_rb_private *) bitmap->private; |
835 | 0 | n = &bp->root.rb_node; |
836 | 0 | start -= bitmap->start; |
837 | 0 | end -= bitmap->start; |
838 | |
|
839 | 0 | if (start > end) |
840 | 0 | return EINVAL; |
841 | | |
842 | 0 | if (ext2fs_rb_empty_root(&bp->root)) |
843 | 0 | return ENOENT; |
844 | | |
845 | 0 | while (*n) { |
846 | 0 | parent = *n; |
847 | 0 | ext = node_to_extent(parent); |
848 | 0 | if (start < ext->start) { |
849 | 0 | n = &(*n)->rb_left; |
850 | 0 | } else if (start >= (ext->start + ext->count)) { |
851 | 0 | n = &(*n)->rb_right; |
852 | 0 | } else if (ext->start + ext->count <= end) { |
853 | 0 | *out = ext->start + ext->count + bitmap->start; |
854 | 0 | return 0; |
855 | 0 | } else |
856 | 0 | return ENOENT; |
857 | 0 | } |
858 | | |
859 | 0 | *out = start + bitmap->start; |
860 | 0 | return 0; |
861 | 0 | } |
862 | | |
863 | | static errcode_t rb_find_first_set(ext2fs_generic_bitmap_64 bitmap, |
864 | | __u64 start, __u64 end, __u64 *out) |
865 | 0 | { |
866 | 0 | struct rb_node *parent = NULL, **n; |
867 | 0 | struct rb_node *node; |
868 | 0 | struct ext2fs_rb_private *bp; |
869 | 0 | struct bmap_rb_extent *ext; |
870 | |
|
871 | 0 | bp = (struct ext2fs_rb_private *) bitmap->private; |
872 | 0 | n = &bp->root.rb_node; |
873 | 0 | start -= bitmap->start; |
874 | 0 | end -= bitmap->start; |
875 | |
|
876 | 0 | if (start > end) |
877 | 0 | return EINVAL; |
878 | | |
879 | 0 | if (ext2fs_rb_empty_root(&bp->root)) |
880 | 0 | return ENOENT; |
881 | | |
882 | 0 | while (*n) { |
883 | 0 | parent = *n; |
884 | 0 | ext = node_to_extent(parent); |
885 | 0 | if (start < ext->start) { |
886 | 0 | n = &(*n)->rb_left; |
887 | 0 | } else if (start >= (ext->start + ext->count)) { |
888 | 0 | n = &(*n)->rb_right; |
889 | 0 | } else { |
890 | | /* The start bit is set */ |
891 | 0 | *out = start + bitmap->start; |
892 | 0 | return 0; |
893 | 0 | } |
894 | 0 | } |
895 | | |
896 | 0 | node = parent; |
897 | 0 | ext = node_to_extent(node); |
898 | 0 | if (ext->start < start) { |
899 | 0 | node = ext2fs_rb_next(node); |
900 | 0 | if (node == NULL) |
901 | 0 | return ENOENT; |
902 | 0 | ext = node_to_extent(node); |
903 | 0 | } |
904 | 0 | if (ext->start <= end) { |
905 | 0 | *out = ext->start + bitmap->start; |
906 | 0 | return 0; |
907 | 0 | } |
908 | 0 | return ENOENT; |
909 | 0 | } |
910 | | |
911 | | #ifdef ENABLE_BMAP_STATS |
912 | | static void rb_print_stats(ext2fs_generic_bitmap_64 bitmap) |
913 | 0 | { |
914 | 0 | struct ext2fs_rb_private *bp; |
915 | 0 | struct rb_node *node = NULL; |
916 | 0 | struct bmap_rb_extent *ext; |
917 | 0 | __u64 count = 0; |
918 | 0 | __u64 max_size = 0; |
919 | 0 | __u64 min_size = ULONG_MAX; |
920 | 0 | __u64 size = 0, avg_size = 0; |
921 | 0 | double eff; |
922 | | #ifdef ENABLE_BMAP_STATS_OPS |
923 | | __u64 mark_all, test_all; |
924 | | double m_hit = 0.0, t_hit = 0.0; |
925 | | #endif |
926 | |
|
927 | 0 | bp = (struct ext2fs_rb_private *) bitmap->private; |
928 | |
|
929 | 0 | for (node = ext2fs_rb_first(&bp->root); node != NULL; |
930 | 0 | node = ext2fs_rb_next(node)) { |
931 | 0 | ext = node_to_extent(node); |
932 | 0 | count++; |
933 | 0 | if (ext->count > max_size) |
934 | 0 | max_size = ext->count; |
935 | 0 | if (ext->count < min_size) |
936 | 0 | min_size = ext->count; |
937 | 0 | size += ext->count; |
938 | 0 | } |
939 | |
|
940 | 0 | if (count) |
941 | 0 | avg_size = size / count; |
942 | 0 | if (min_size == ULONG_MAX) |
943 | 0 | min_size = 0; |
944 | 0 | eff = (double)((count * sizeof(struct bmap_rb_extent)) << 3) / |
945 | 0 | (bitmap->real_end - bitmap->start); |
946 | | #ifdef ENABLE_BMAP_STATS_OPS |
947 | | mark_all = bitmap->stats.mark_count + bitmap->stats.mark_ext_count; |
948 | | test_all = bitmap->stats.test_count + bitmap->stats.test_ext_count; |
949 | | if (mark_all) |
950 | | m_hit = ((double)bp->mark_hit / mark_all) * 100; |
951 | | if (test_all) |
952 | | t_hit = ((double)bp->test_hit / test_all) * 100; |
953 | | |
954 | | fprintf(stderr, "%16llu cache hits on test (%.2f%%)\n" |
955 | | "%16llu cache hits on mark (%.2f%%)\n", |
956 | | bp->test_hit, t_hit, bp->mark_hit, m_hit); |
957 | | #endif |
958 | 0 | fprintf(stderr, "%16llu extents (%llu bytes)\n", |
959 | 0 | (unsigned long long) count, (unsigned long long) |
960 | 0 | ((count * sizeof(struct bmap_rb_extent)) + |
961 | 0 | sizeof(struct ext2fs_rb_private))); |
962 | 0 | fprintf(stderr, "%16llu bits minimum size\n", |
963 | 0 | (unsigned long long) min_size); |
964 | 0 | fprintf(stderr, "%16llu bits maximum size\n" |
965 | 0 | "%16llu bits average size\n", |
966 | 0 | (unsigned long long) max_size, (unsigned long long) avg_size); |
967 | 0 | fprintf(stderr, "%16llu bits set in bitmap (out of %llu)\n", |
968 | 0 | (unsigned long long) size, |
969 | 0 | (unsigned long long) bitmap->real_end - bitmap->start); |
970 | | fprintf(stderr, |
971 | 0 | "%16.4lf memory / bitmap bit memory ratio (bitarray = 1)\n", |
972 | 0 | eff); |
973 | 0 | } |
974 | | #else |
975 | | static void rb_print_stats(ext2fs_generic_bitmap_64 bitmap EXT2FS_ATTR((unused))) |
976 | | { |
977 | | } |
978 | | #endif |
979 | | |
980 | | struct ext2_bitmap_ops ext2fs_blkmap64_rbtree = { |
981 | | .type = EXT2FS_BMAP64_RBTREE, |
982 | | .new_bmap = rb_new_bmap, |
983 | | .free_bmap = rb_free_bmap, |
984 | | .copy_bmap = rb_copy_bmap, |
985 | | .resize_bmap = rb_resize_bmap, |
986 | | .mark_bmap = rb_mark_bmap, |
987 | | .unmark_bmap = rb_unmark_bmap, |
988 | | .test_bmap = rb_test_bmap, |
989 | | .test_clear_bmap_extent = rb_test_clear_bmap_extent, |
990 | | .mark_bmap_extent = rb_mark_bmap_extent, |
991 | | .unmark_bmap_extent = rb_unmark_bmap_extent, |
992 | | .set_bmap_range = rb_set_bmap_range, |
993 | | .get_bmap_range = rb_get_bmap_range, |
994 | | .clear_bmap = rb_clear_bmap, |
995 | | .print_stats = rb_print_stats, |
996 | | .find_first_zero = rb_find_first_zero, |
997 | | .find_first_set = rb_find_first_set, |
998 | | }; |