Coverage Report

Created: 2026-04-29 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
};