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