1 /* 2 * gen_bitmap64.c --- routines to read, write, and manipulate the new qinode and 3 * block bitmaps. 4 * 5 * Copyright (C) 2007, 2008 Theodore Ts'o. 6 * 7 * %Begin-Header% 8 * This file may be redistributed under the terms of the GNU Public 9 * License. 10 * %End-Header% 11 */ 12 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 #include <errno.h> 21 #if HAVE_SYS_STAT_H 22 #include <sys/stat.h> 23 #endif 24 #if HAVE_SYS_TYPES_H 25 #include <sys/types.h> 26 #endif 27 #ifdef HAVE_SYS_TIME_H 28 #include <sys/time.h> 29 #endif 30 31 #include "ext2_fs.h" 32 #include "ext2fsP.h" 33 #include "bmap64.h" 34 35 /* 36 * Design of 64-bit bitmaps 37 * 38 * In order maintain ABI compatibility with programs that don't 39 * understand about 64-bit blocks/inodes, 40 * ext2fs_allocate_inode_bitmap() and ext2fs_allocate_block_bitmap() 41 * will create old-style bitmaps unless the application passes the 42 * flag EXT2_FLAG_64BITS to ext2fs_open(). If this flag is 43 * passed, then we know the application has been recompiled, so we can 44 * use the new-style bitmaps. If it is not passed, we have to return 45 * an error if trying to open a filesystem which needs 64-bit bitmaps. 46 * 47 * The new bitmaps use a new set of structure magic numbers, so that 48 * both the old-style and new-style interfaces can identify which 49 * version of the data structure was used. Both the old-style and 50 * new-style interfaces will support either type of bitmap, although 51 * of course 64-bit operation will only be possible when both the 52 * new-style interface and the new-style bitmap are used. 53 * 54 * For example, the new bitmap interfaces will check the structure 55 * magic numbers and so will be able to detect old-stype bitmap. If 56 * they see an old-style bitmap, they will pass it to the gen_bitmap.c 57 * functions for handling. The same will be true for the old 58 * interfaces as well. 59 * 60 * The new-style interfaces will have several different back-end 61 * implementations, so we can support different encodings that are 62 * appropriate for different applications. In general the default 63 * should be whatever makes sense, and what the application/library 64 * will use. However, e2fsck may need specialized implementations for 65 * its own uses. For example, when doing parent directory pointer 66 * loop detections in pass 3, the bitmap will *always* be sparse, so 67 * e2fsck can request an encoding which is optimized for that. 68 */ 69 70 static void warn_bitmap(ext2fs_generic_bitmap bitmap, 71 int code, __u64 arg) 72 { 73 #ifndef OMIT_COM_ERR 74 if (bitmap->description) 75 com_err(0, bitmap->base_error_code+code, 76 "#%llu for %s", arg, bitmap->description); 77 else 78 com_err(0, bitmap->base_error_code + code, "#%llu", arg); 79 #endif 80 } 81 82 #ifdef BMAP_STATS_OPS 83 #define INC_STAT(map, name) map->stats.name 84 #else 85 #define INC_STAT(map, name) ;; 86 #endif 87 88 89 errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic, 90 int type, __u64 start, __u64 end, 91 __u64 real_end, 92 const char *descr, 93 ext2fs_generic_bitmap *ret) 94 { 95 ext2fs_generic_bitmap bitmap; 96 struct ext2_bitmap_ops *ops; 97 ext2_ino_t num_dirs; 98 errcode_t retval; 99 100 if (!type) 101 type = EXT2FS_BMAP64_BITARRAY; 102 103 switch (type) { 104 case EXT2FS_BMAP64_BITARRAY: 105 ops = &ext2fs_blkmap64_bitarray; 106 break; 107 case EXT2FS_BMAP64_RBTREE: 108 ops = &ext2fs_blkmap64_rbtree; 109 break; 110 case EXT2FS_BMAP64_AUTODIR: 111 retval = ext2fs_get_num_dirs(fs, &num_dirs); 112 if (retval || num_dirs > (fs->super->s_inodes_count / 320)) 113 ops = &ext2fs_blkmap64_bitarray; 114 else 115 ops = &ext2fs_blkmap64_rbtree; 116 break; 117 default: 118 return EINVAL; 119 } 120 121 retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap), 122 &bitmap); 123 if (retval) 124 return retval; 125 126 #ifdef BMAP_STATS 127 if (gettimeofday(&bitmap->stats.created, 128 (struct timezone *) NULL) == -1) { 129 perror("gettimeofday"); 130 ext2fs_free_mem(&bitmap); 131 return 1; 132 } 133 bitmap->stats.type = type; 134 #endif 135 136 /* XXX factor out, repeated in copy_bmap */ 137 bitmap->magic = magic; 138 bitmap->fs = fs; 139 bitmap->start = start; 140 bitmap->end = end; 141 bitmap->real_end = real_end; 142 bitmap->bitmap_ops = ops; 143 bitmap->cluster_bits = 0; 144 switch (magic) { 145 case EXT2_ET_MAGIC_INODE_BITMAP64: 146 bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK; 147 break; 148 case EXT2_ET_MAGIC_BLOCK_BITMAP64: 149 bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK; 150 bitmap->cluster_bits = fs->cluster_ratio_bits; 151 break; 152 default: 153 bitmap->base_error_code = EXT2_ET_BAD_GENERIC_MARK; 154 } 155 if (descr) { 156 retval = ext2fs_get_mem(strlen(descr)+1, &bitmap->description); 157 if (retval) { 158 ext2fs_free_mem(&bitmap); 159 return retval; 160 } 161 strcpy(bitmap->description, descr); 162 } else 163 bitmap->description = 0; 164 165 retval = bitmap->bitmap_ops->new_bmap(fs, bitmap); 166 if (retval) { 167 ext2fs_free_mem(&bitmap->description); 168 ext2fs_free_mem(&bitmap); 169 return retval; 170 } 171 172 *ret = bitmap; 173 return 0; 174 } 175 176 #ifdef BMAP_STATS 177 static void ext2fs_print_bmap_statistics(ext2fs_generic_bitmap bitmap) 178 { 179 struct ext2_bmap_statistics *stats = &bitmap->stats; 180 #ifdef BMAP_STATS_OPS 181 float mark_seq_perc = 0.0, test_seq_perc = 0.0; 182 float mark_back_perc = 0.0, test_back_perc = 0.0; 183 #endif 184 double inuse; 185 struct timeval now; 186 187 #ifdef BMAP_STATS_OPS 188 if (stats->test_count) { 189 test_seq_perc = ((float)stats->test_seq / 190 stats->test_count) * 100; 191 test_back_perc = ((float)stats->test_back / 192 stats->test_count) * 100; 193 } 194 195 if (stats->mark_count) { 196 mark_seq_perc = ((float)stats->mark_seq / 197 stats->mark_count) * 100; 198 mark_back_perc = ((float)stats->mark_back / 199 stats->mark_count) * 100; 200 } 201 #endif 202 203 if (gettimeofday(&now, (struct timezone *) NULL) == -1) { 204 perror("gettimeofday"); 205 return; 206 } 207 208 inuse = (double) now.tv_sec + \ 209 (((double) now.tv_usec) * 0.000001); 210 inuse -= (double) stats->created.tv_sec + \ 211 (((double) stats->created.tv_usec) * 0.000001); 212 213 fprintf(stderr, "\n[+] %s bitmap (type %d)\n", bitmap->description, 214 stats->type); 215 fprintf(stderr, "=================================================\n"); 216 #ifdef BMAP_STATS_OPS 217 fprintf(stderr, "%16llu bits long\n", 218 bitmap->real_end - bitmap->start); 219 fprintf(stderr, "%16lu copy_bmap\n%16lu resize_bmap\n", 220 stats->copy_count, stats->resize_count); 221 fprintf(stderr, "%16lu mark bmap\n%16lu unmark_bmap\n", 222 stats->mark_count, stats->unmark_count); 223 fprintf(stderr, "%16lu test_bmap\n%16lu mark_bmap_extent\n", 224 stats->test_count, stats->mark_ext_count); 225 fprintf(stderr, "%16lu unmark_bmap_extent\n" 226 "%16lu test_clear_bmap_extent\n", 227 stats->unmark_ext_count, stats->test_ext_count); 228 fprintf(stderr, "%16lu set_bmap_range\n%16lu set_bmap_range\n", 229 stats->set_range_count, stats->get_range_count); 230 fprintf(stderr, "%16lu clear_bmap\n%16lu contiguous bit test (%.2f%%)\n", 231 stats->clear_count, stats->test_seq, test_seq_perc); 232 fprintf(stderr, "%16lu contiguous bit mark (%.2f%%)\n" 233 "%16llu bits tested backwards (%.2f%%)\n", 234 stats->mark_seq, mark_seq_perc, 235 stats->test_back, test_back_perc); 236 fprintf(stderr, "%16llu bits marked backwards (%.2f%%)\n" 237 "%16.2f seconds in use\n", 238 stats->mark_back, mark_back_perc, inuse); 239 #endif /* BMAP_STATS_OPS */ 240 } 241 #endif 242 243 void ext2fs_free_generic_bmap(ext2fs_generic_bitmap bmap) 244 { 245 if (!bmap) 246 return; 247 248 if (EXT2FS_IS_32_BITMAP(bmap)) { 249 ext2fs_free_generic_bitmap(bmap); 250 return; 251 } 252 253 if (!EXT2FS_IS_64_BITMAP(bmap)) 254 return; 255 256 #ifdef BMAP_STATS 257 if (getenv("E2FSPROGS_BITMAP_STATS")) { 258 ext2fs_print_bmap_statistics(bmap); 259 bmap->bitmap_ops->print_stats(bmap); 260 } 261 #endif 262 263 bmap->bitmap_ops->free_bmap(bmap); 264 265 if (bmap->description) { 266 ext2fs_free_mem(&bmap->description); 267 bmap->description = 0; 268 } 269 bmap->magic = 0; 270 ext2fs_free_mem(&bmap); 271 } 272 273 errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap src, 274 ext2fs_generic_bitmap *dest) 275 { 276 char *descr, *new_descr; 277 ext2fs_generic_bitmap new_bmap; 278 errcode_t retval; 279 280 if (!src) 281 return EINVAL; 282 283 if (EXT2FS_IS_32_BITMAP(src)) 284 return ext2fs_copy_generic_bitmap(src, dest); 285 286 if (!EXT2FS_IS_64_BITMAP(src)) 287 return EINVAL; 288 289 /* Allocate a new bitmap struct */ 290 retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap), 291 &new_bmap); 292 if (retval) 293 return retval; 294 295 296 #ifdef BMAP_STATS_OPS 297 src->stats.copy_count++; 298 #endif 299 #ifdef BMAP_STATS 300 if (gettimeofday(&new_bmap->stats.created, 301 (struct timezone *) NULL) == -1) { 302 perror("gettimeofday"); 303 ext2fs_free_mem(&new_bmap); 304 return 1; 305 } 306 new_bmap->stats.type = src->stats.type; 307 #endif 308 309 /* Copy all the high-level parts over */ 310 new_bmap->magic = src->magic; 311 new_bmap->fs = src->fs; 312 new_bmap->start = src->start; 313 new_bmap->end = src->end; 314 new_bmap->real_end = src->real_end; 315 new_bmap->bitmap_ops = src->bitmap_ops; 316 new_bmap->base_error_code = src->base_error_code; 317 new_bmap->cluster_bits = src->cluster_bits; 318 319 descr = src->description; 320 if (descr) { 321 retval = ext2fs_get_mem(strlen(descr)+10, &new_descr); 322 if (retval) { 323 ext2fs_free_mem(&new_bmap); 324 return retval; 325 } 326 sprintf(new_descr, "copy of %s", descr); 327 new_bmap->description = new_descr; 328 } 329 330 retval = src->bitmap_ops->copy_bmap(src, new_bmap); 331 if (retval) { 332 ext2fs_free_mem(&new_bmap->description); 333 ext2fs_free_mem(&new_bmap); 334 return retval; 335 } 336 337 *dest = new_bmap; 338 339 return 0; 340 } 341 342 errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap bmap, 343 __u64 new_end, 344 __u64 new_real_end) 345 { 346 if (!bmap) 347 return EINVAL; 348 349 if (EXT2FS_IS_32_BITMAP(bmap)) 350 return ext2fs_resize_generic_bitmap(bmap->magic, new_end, 351 new_real_end, bmap); 352 353 if (!EXT2FS_IS_64_BITMAP(bmap)) 354 return EINVAL; 355 356 INC_STAT(bmap, resize_count); 357 358 return bmap->bitmap_ops->resize_bmap(bmap, new_end, new_real_end); 359 } 360 361 errcode_t ext2fs_fudge_generic_bmap_end(ext2fs_generic_bitmap bitmap, 362 errcode_t neq, 363 __u64 end, __u64 *oend) 364 { 365 if (!bitmap) 366 return EINVAL; 367 368 if (EXT2FS_IS_32_BITMAP(bitmap)) { 369 ext2_ino_t tmp_oend; 370 int retval; 371 372 retval = ext2fs_fudge_generic_bitmap_end(bitmap, bitmap->magic, 373 neq, end, &tmp_oend); 374 if (oend) 375 *oend = tmp_oend; 376 return retval; 377 } 378 379 if (!EXT2FS_IS_64_BITMAP(bitmap)) 380 return EINVAL; 381 382 if (end > bitmap->real_end) 383 return neq; 384 if (oend) 385 *oend = bitmap->end; 386 bitmap->end = end; 387 return 0; 388 } 389 390 __u64 ext2fs_get_generic_bmap_start(ext2fs_generic_bitmap bitmap) 391 { 392 if (!bitmap) 393 return EINVAL; 394 395 if (EXT2FS_IS_32_BITMAP(bitmap)) 396 return ext2fs_get_generic_bitmap_start(bitmap); 397 398 if (!EXT2FS_IS_64_BITMAP(bitmap)) 399 return EINVAL; 400 401 return bitmap->start; 402 } 403 404 __u64 ext2fs_get_generic_bmap_end(ext2fs_generic_bitmap bitmap) 405 { 406 if (!bitmap) 407 return EINVAL; 408 409 if (EXT2FS_IS_32_BITMAP(bitmap)) 410 return ext2fs_get_generic_bitmap_end(bitmap); 411 412 if (!EXT2FS_IS_64_BITMAP(bitmap)) 413 return EINVAL; 414 415 return bitmap->end; 416 } 417 418 void ext2fs_clear_generic_bmap(ext2fs_generic_bitmap bitmap) 419 { 420 if (EXT2FS_IS_32_BITMAP(bitmap)) 421 ext2fs_clear_generic_bitmap(bitmap); 422 else 423 bitmap->bitmap_ops->clear_bmap (bitmap); 424 } 425 426 int ext2fs_mark_generic_bmap(ext2fs_generic_bitmap bitmap, 427 __u64 arg) 428 { 429 if (!bitmap) 430 return 0; 431 432 if (EXT2FS_IS_32_BITMAP(bitmap)) { 433 if (arg & ~0xffffffffULL) { 434 ext2fs_warn_bitmap2(bitmap, 435 EXT2FS_MARK_ERROR, 0xffffffff); 436 return 0; 437 } 438 return ext2fs_mark_generic_bitmap(bitmap, arg); 439 } 440 441 if (!EXT2FS_IS_64_BITMAP(bitmap)) 442 return 0; 443 444 arg >>= bitmap->cluster_bits; 445 446 #ifdef BMAP_STATS_OPS 447 if (arg == bitmap->stats.last_marked + 1) 448 bitmap->stats.mark_seq++; 449 if (arg < bitmap->stats.last_marked) 450 bitmap->stats.mark_back++; 451 bitmap->stats.last_marked = arg; 452 bitmap->stats.mark_count++; 453 #endif 454 455 if ((arg < bitmap->start) || (arg > bitmap->end)) { 456 warn_bitmap(bitmap, EXT2FS_MARK_ERROR, arg); 457 return 0; 458 } 459 460 return bitmap->bitmap_ops->mark_bmap(bitmap, arg); 461 } 462 463 int ext2fs_unmark_generic_bmap(ext2fs_generic_bitmap bitmap, 464 __u64 arg) 465 { 466 if (!bitmap) 467 return 0; 468 469 if (EXT2FS_IS_32_BITMAP(bitmap)) { 470 if (arg & ~0xffffffffULL) { 471 ext2fs_warn_bitmap2(bitmap, EXT2FS_UNMARK_ERROR, 472 0xffffffff); 473 return 0; 474 } 475 return ext2fs_unmark_generic_bitmap(bitmap, arg); 476 } 477 478 if (!EXT2FS_IS_64_BITMAP(bitmap)) 479 return 0; 480 481 arg >>= bitmap->cluster_bits; 482 483 INC_STAT(bitmap, unmark_count); 484 485 if ((arg < bitmap->start) || (arg > bitmap->end)) { 486 warn_bitmap(bitmap, EXT2FS_UNMARK_ERROR, arg); 487 return 0; 488 } 489 490 return bitmap->bitmap_ops->unmark_bmap(bitmap, arg); 491 } 492 493 int ext2fs_test_generic_bmap(ext2fs_generic_bitmap bitmap, 494 __u64 arg) 495 { 496 if (!bitmap) 497 return 0; 498 499 if (EXT2FS_IS_32_BITMAP(bitmap)) { 500 if (arg & ~0xffffffffULL) { 501 ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, 502 0xffffffff); 503 return 0; 504 } 505 return ext2fs_test_generic_bitmap(bitmap, arg); 506 } 507 508 if (!EXT2FS_IS_64_BITMAP(bitmap)) 509 return 0; 510 511 arg >>= bitmap->cluster_bits; 512 513 #ifdef BMAP_STATS_OPS 514 bitmap->stats.test_count++; 515 if (arg == bitmap->stats.last_tested + 1) 516 bitmap->stats.test_seq++; 517 if (arg < bitmap->stats.last_tested) 518 bitmap->stats.test_back++; 519 bitmap->stats.last_tested = arg; 520 #endif 521 522 if ((arg < bitmap->start) || (arg > bitmap->end)) { 523 warn_bitmap(bitmap, EXT2FS_TEST_ERROR, arg); 524 return 0; 525 } 526 527 return bitmap->bitmap_ops->test_bmap(bitmap, arg); 528 } 529 530 errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap bmap, 531 __u64 start, unsigned int num, 532 void *in) 533 { 534 if (!bmap) 535 return EINVAL; 536 537 if (EXT2FS_IS_32_BITMAP(bmap)) { 538 if ((start+num-1) & ~0xffffffffULL) { 539 ext2fs_warn_bitmap2(bmap, EXT2FS_UNMARK_ERROR, 540 0xffffffff); 541 return EINVAL; 542 } 543 return ext2fs_set_generic_bitmap_range(bmap, bmap->magic, 544 start, num, in); 545 } 546 547 if (!EXT2FS_IS_64_BITMAP(bmap)) 548 return EINVAL; 549 550 INC_STAT(bmap, set_range_count); 551 552 return bmap->bitmap_ops->set_bmap_range(bmap, start, num, in); 553 } 554 555 errcode_t ext2fs_get_generic_bmap_range(ext2fs_generic_bitmap bmap, 556 __u64 start, unsigned int num, 557 void *out) 558 { 559 if (!bmap) 560 return EINVAL; 561 562 if (EXT2FS_IS_32_BITMAP(bmap)) { 563 if ((start+num-1) & ~0xffffffffULL) { 564 ext2fs_warn_bitmap2(bmap, 565 EXT2FS_UNMARK_ERROR, 0xffffffff); 566 return EINVAL; 567 } 568 return ext2fs_get_generic_bitmap_range(bmap, bmap->magic, 569 start, num, out); 570 } 571 572 if (!EXT2FS_IS_64_BITMAP(bmap)) 573 return EINVAL; 574 575 INC_STAT(bmap, get_range_count); 576 577 return bmap->bitmap_ops->get_bmap_range(bmap, start, num, out); 578 } 579 580 errcode_t ext2fs_compare_generic_bmap(errcode_t neq, 581 ext2fs_generic_bitmap bm1, 582 ext2fs_generic_bitmap bm2) 583 { 584 blk64_t i; 585 586 if (!bm1 || !bm2) 587 return EINVAL; 588 if (bm1->magic != bm2->magic) 589 return EINVAL; 590 591 /* Now we know both bitmaps have the same magic */ 592 if (EXT2FS_IS_32_BITMAP(bm1)) 593 return ext2fs_compare_generic_bitmap(bm1->magic, neq, bm1, bm2); 594 595 if (!EXT2FS_IS_64_BITMAP(bm1)) 596 return EINVAL; 597 598 if ((bm1->start != bm2->start) || 599 (bm1->end != bm2->end)) 600 return neq; 601 602 for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++) 603 if (ext2fs_test_generic_bmap(bm1, i) != 604 ext2fs_test_generic_bmap(bm2, i)) 605 return neq; 606 607 return 0; 608 } 609 610 void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap bmap) 611 { 612 __u64 start, num; 613 614 if (EXT2FS_IS_32_BITMAP(bmap)) { 615 ext2fs_set_generic_bitmap_padding(bmap); 616 return; 617 } 618 619 start = bmap->end + 1; 620 num = bmap->real_end - bmap->end; 621 bmap->bitmap_ops->mark_bmap_extent(bmap, start, num); 622 /* XXX ought to warn on error */ 623 } 624 625 int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap bmap, 626 blk64_t block, unsigned int num) 627 { 628 __u64 end = block + num; 629 630 if (!bmap) 631 return EINVAL; 632 633 if (num == 1) 634 return !ext2fs_test_generic_bmap((ext2fs_generic_bitmap) 635 bmap, block); 636 637 if (EXT2FS_IS_32_BITMAP(bmap)) { 638 if ((block+num-1) & ~0xffffffffULL) { 639 ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap, 640 EXT2FS_UNMARK_ERROR, 0xffffffff); 641 return EINVAL; 642 } 643 return ext2fs_test_block_bitmap_range( 644 (ext2fs_generic_bitmap) bmap, block, num); 645 } 646 647 if (!EXT2FS_IS_64_BITMAP(bmap)) 648 return EINVAL; 649 650 INC_STAT(bmap, test_ext_count); 651 652 /* convert to clusters if necessary */ 653 block >>= bmap->cluster_bits; 654 end += (1 << bmap->cluster_bits) - 1; 655 end >>= bmap->cluster_bits; 656 num = end - block; 657 658 if ((block < bmap->start) || (block+num-1 > bmap->end)) { 659 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST, block, 660 bmap->description); 661 return EINVAL; 662 } 663 664 return bmap->bitmap_ops->test_clear_bmap_extent(bmap, block, num); 665 } 666 667 void ext2fs_mark_block_bitmap_range2(ext2fs_block_bitmap bmap, 668 blk64_t block, unsigned int num) 669 { 670 __u64 end = block + num; 671 672 if (!bmap) 673 return; 674 675 if (EXT2FS_IS_32_BITMAP(bmap)) { 676 if ((block+num-1) & ~0xffffffffULL) { 677 ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap, 678 EXT2FS_UNMARK_ERROR, 0xffffffff); 679 return; 680 } 681 ext2fs_mark_block_bitmap_range((ext2fs_generic_bitmap) bmap, 682 block, num); 683 } 684 685 if (!EXT2FS_IS_64_BITMAP(bmap)) 686 return; 687 688 INC_STAT(bmap, mark_ext_count); 689 690 /* convert to clusters if necessary */ 691 block >>= bmap->cluster_bits; 692 end += (1 << bmap->cluster_bits) - 1; 693 end >>= bmap->cluster_bits; 694 num = end - block; 695 696 if ((block < bmap->start) || (block+num-1 > bmap->end)) { 697 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block, 698 bmap->description); 699 return; 700 } 701 702 bmap->bitmap_ops->mark_bmap_extent(bmap, block, num); 703 } 704 705 void ext2fs_unmark_block_bitmap_range2(ext2fs_block_bitmap bmap, 706 blk64_t block, unsigned int num) 707 { 708 __u64 end = block + num; 709 710 if (!bmap) 711 return; 712 713 if (EXT2FS_IS_32_BITMAP(bmap)) { 714 if ((block+num-1) & ~0xffffffffULL) { 715 ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap, 716 EXT2FS_UNMARK_ERROR, 0xffffffff); 717 return; 718 } 719 ext2fs_unmark_block_bitmap_range((ext2fs_generic_bitmap) bmap, 720 block, num); 721 } 722 723 if (!EXT2FS_IS_64_BITMAP(bmap)) 724 return; 725 726 INC_STAT(bmap, unmark_ext_count); 727 728 /* convert to clusters if necessary */ 729 block >>= bmap->cluster_bits; 730 end += (1 << bmap->cluster_bits) - 1; 731 end >>= bmap->cluster_bits; 732 num = end - block; 733 734 if ((block < bmap->start) || (block+num-1 > bmap->end)) { 735 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block, 736 bmap->description); 737 return; 738 } 739 740 bmap->bitmap_ops->unmark_bmap_extent(bmap, block, num); 741 } 742 743 void ext2fs_warn_bitmap32(ext2fs_generic_bitmap bitmap, const char *func) 744 { 745 #ifndef OMIT_COM_ERR 746 if (bitmap && bitmap->description) 747 com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, 748 "called %s with 64-bit bitmap for %s", func, 749 bitmap->description); 750 else 751 com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, 752 "called %s with 64-bit bitmap", func); 753 #endif 754 } 755 756 errcode_t ext2fs_convert_subcluster_bitmap(ext2_filsys fs, 757 ext2fs_block_bitmap *bitmap) 758 { 759 ext2fs_block_bitmap cmap, bmap; 760 errcode_t retval; 761 blk64_t i, b_end, c_end; 762 int n, ratio; 763 764 bmap = *bitmap; 765 766 if (fs->cluster_ratio_bits == ext2fs_get_bitmap_granularity(bmap)) 767 return 0; /* Nothing to do */ 768 769 retval = ext2fs_allocate_block_bitmap(fs, "converted cluster bitmap", 770 &cmap); 771 if (retval) 772 return retval; 773 774 i = bmap->start; 775 b_end = bmap->end; 776 bmap->end = bmap->real_end; 777 c_end = cmap->end; 778 cmap->end = cmap->real_end; 779 n = 0; 780 ratio = 1 << fs->cluster_ratio_bits; 781 while (i < bmap->real_end) { 782 if (ext2fs_test_block_bitmap2(bmap, i)) { 783 ext2fs_mark_block_bitmap2(cmap, i); 784 i += ratio - n; 785 n = 0; 786 continue; 787 } 788 i++; n++; 789 if (n >= ratio) 790 n = 0; 791 } 792 bmap->end = b_end; 793 cmap->end = c_end; 794 ext2fs_free_block_bitmap(bmap); 795 *bitmap = cmap; 796 return 0; 797 } 798 799 errcode_t ext2fs_find_first_zero_generic_bmap(ext2fs_generic_bitmap bitmap, 800 __u64 start, __u64 end, __u64 *out) 801 { 802 int b; 803 804 if (!bitmap) 805 return EINVAL; 806 807 if (EXT2FS_IS_64_BITMAP(bitmap) && bitmap->bitmap_ops->find_first_zero) 808 return bitmap->bitmap_ops->find_first_zero(bitmap, start, 809 end, out); 810 811 if (EXT2FS_IS_32_BITMAP(bitmap)) { 812 blk_t blk = 0; 813 errcode_t retval; 814 815 if (((start) & ~0xffffffffULL) || 816 ((end) & ~0xffffffffULL)) { 817 ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start); 818 return EINVAL; 819 } 820 821 retval = ext2fs_find_first_zero_generic_bitmap(bitmap, start, 822 end, &blk); 823 if (retval == 0) 824 *out = blk; 825 return retval; 826 } 827 828 if (!EXT2FS_IS_64_BITMAP(bitmap)) 829 return EINVAL; 830 831 start >>= bitmap->cluster_bits; 832 end >>= bitmap->cluster_bits; 833 834 if (start < bitmap->start || end > bitmap->end || start > end) { 835 warn_bitmap(bitmap, EXT2FS_TEST_ERROR, start); 836 return EINVAL; 837 } 838 839 while (start <= end) { 840 b = bitmap->bitmap_ops->test_bmap(bitmap, start); 841 if (!b) { 842 *out = start << bitmap->cluster_bits; 843 return 0; 844 } 845 start++; 846 } 847 848 return ENOENT; 849 } 850