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