gen_bitmap64.c revision d182831a15dfa4d36979be10fdfd4ec06bdd65b9
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 "config.h" 14#include <stdio.h> 15#include <string.h> 16#if HAVE_UNISTD_H 17#include <unistd.h> 18#endif 19#include <fcntl.h> 20#include <time.h> 21#include <errno.h> 22#if HAVE_SYS_STAT_H 23#include <sys/stat.h> 24#endif 25#if HAVE_SYS_TYPES_H 26#include <sys/types.h> 27#endif 28 29#include "ext2_fs.h" 30#include "ext2fsP.h" 31#include "bmap64.h" 32 33/* 34 * Design of 64-bit bitmaps 35 * 36 * In order maintain ABI compatibility with programs that don't 37 * understand about 64-bit blocks/inodes, 38 * ext2fs_allocate_inode_bitmap() and ext2fs_allocate_block_bitmap() 39 * will create old-style bitmaps unless the application passes the 40 * flag EXT2_FLAG_64BITS to ext2fs_open(). If this flag is 41 * passed, then we know the application has been recompiled, so we can 42 * use the new-style bitmaps. If it is not passed, we have to return 43 * an error if trying to open a filesystem which needs 64-bit bitmaps. 44 * 45 * The new bitmaps use a new set of structure magic numbers, so that 46 * both the old-style and new-style interfaces can identify which 47 * version of the data structure was used. Both the old-style and 48 * new-style interfaces will support either type of bitmap, although 49 * of course 64-bit operation will only be possible when both the 50 * new-style interface and the new-style bitmap are used. 51 * 52 * For example, the new bitmap interfaces will check the structure 53 * magic numbers and so will be able to detect old-stype bitmap. If 54 * they see an old-style bitmap, they will pass it to the gen_bitmap.c 55 * functions for handling. The same will be true for the old 56 * interfaces as well. 57 * 58 * The new-style interfaces will have several different back-end 59 * implementations, so we can support different encodings that are 60 * appropriate for different applications. In general the default 61 * should be whatever makes sense, and what the application/library 62 * will use. However, e2fsck may need specialized implementations for 63 * its own uses. For example, when doing parent directory pointer 64 * loop detections in pass 3, the bitmap will *always* be sparse, so 65 * e2fsck can request an encoding which is optimized for that. 66 */ 67 68static void warn_bitmap(ext2fs_generic_bitmap bitmap, 69 int code, __u64 arg) 70{ 71#ifndef OMIT_COM_ERR 72 if (bitmap->description) 73 com_err(0, bitmap->base_error_code+code, 74 "#%llu for %s", arg, bitmap->description); 75 else 76 com_err(0, bitmap->base_error_code + code, "#%llu", arg); 77#endif 78} 79 80 81errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic, 82 int type, __u64 start, __u64 end, 83 __u64 real_end, 84 const char *descr, 85 ext2fs_generic_bitmap *ret) 86{ 87 ext2fs_generic_bitmap bitmap; 88 struct ext2_bitmap_ops *ops; 89 ext2_ino_t num_dirs; 90 errcode_t retval; 91 92 if (!type) 93 type = EXT2FS_BMAP64_BITARRAY; 94 95 switch (type) { 96 case EXT2FS_BMAP64_BITARRAY: 97 ops = &ext2fs_blkmap64_bitarray; 98 break; 99 case EXT2FS_BMAP64_RBTREE: 100 ops = &ext2fs_blkmap64_rbtree; 101 break; 102 case EXT2FS_BMAP64_AUTODIR: 103 retval = ext2fs_get_num_dirs(fs, &num_dirs); 104 if (retval || num_dirs > (fs->super->s_inodes_count / 320)) 105 ops = &ext2fs_blkmap64_bitarray; 106 else 107 ops = &ext2fs_blkmap64_rbtree; 108 break; 109 default: 110 return EINVAL; 111 } 112 113 retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap), 114 &bitmap); 115 if (retval) 116 return retval; 117 118 /* XXX factor out, repeated in copy_bmap */ 119 bitmap->magic = magic; 120 bitmap->fs = fs; 121 bitmap->start = start; 122 bitmap->end = end; 123 bitmap->real_end = real_end; 124 bitmap->bitmap_ops = ops; 125 bitmap->cluster_bits = 0; 126 switch (magic) { 127 case EXT2_ET_MAGIC_INODE_BITMAP64: 128 bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK; 129 break; 130 case EXT2_ET_MAGIC_BLOCK_BITMAP64: 131 bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK; 132 bitmap->cluster_bits = fs->cluster_ratio_bits; 133 break; 134 default: 135 bitmap->base_error_code = EXT2_ET_BAD_GENERIC_MARK; 136 } 137 if (descr) { 138 retval = ext2fs_get_mem(strlen(descr)+1, &bitmap->description); 139 if (retval) { 140 ext2fs_free_mem(&bitmap); 141 return retval; 142 } 143 strcpy(bitmap->description, descr); 144 } else 145 bitmap->description = 0; 146 147 retval = bitmap->bitmap_ops->new_bmap(fs, bitmap); 148 if (retval) { 149 ext2fs_free_mem(&bitmap->description); 150 ext2fs_free_mem(&bitmap); 151 return retval; 152 } 153 154 *ret = bitmap; 155 return 0; 156} 157 158void ext2fs_free_generic_bmap(ext2fs_generic_bitmap bmap) 159{ 160 if (!bmap) 161 return; 162 163 if (EXT2FS_IS_32_BITMAP(bmap)) { 164 ext2fs_free_generic_bitmap(bmap); 165 return; 166 } 167 168 if (!EXT2FS_IS_64_BITMAP(bmap)) 169 return; 170 171 bmap->bitmap_ops->free_bmap(bmap); 172 173 if (bmap->description) { 174 ext2fs_free_mem(&bmap->description); 175 bmap->description = 0; 176 } 177 bmap->magic = 0; 178 ext2fs_free_mem(&bmap); 179} 180 181errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap src, 182 ext2fs_generic_bitmap *dest) 183{ 184 char *descr, *new_descr; 185 ext2fs_generic_bitmap new_bmap; 186 errcode_t retval; 187 188 if (!src) 189 return EINVAL; 190 191 if (EXT2FS_IS_32_BITMAP(src)) 192 return ext2fs_copy_generic_bitmap(src, dest); 193 194 if (!EXT2FS_IS_64_BITMAP(src)) 195 return EINVAL; 196 197 /* Allocate a new bitmap struct */ 198 retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap), 199 &new_bmap); 200 if (retval) 201 return retval; 202 203 /* Copy all the high-level parts over */ 204 new_bmap->magic = src->magic; 205 new_bmap->fs = src->fs; 206 new_bmap->start = src->start; 207 new_bmap->end = src->end; 208 new_bmap->real_end = src->real_end; 209 new_bmap->bitmap_ops = src->bitmap_ops; 210 new_bmap->base_error_code = src->base_error_code; 211 new_bmap->cluster_bits = src->cluster_bits; 212 213 descr = src->description; 214 if (descr) { 215 retval = ext2fs_get_mem(strlen(descr)+1, &new_descr); 216 if (retval) { 217 ext2fs_free_mem(&new_bmap); 218 return retval; 219 } 220 strcpy(new_descr, descr); 221 new_bmap->description = new_descr; 222 } 223 224 retval = src->bitmap_ops->copy_bmap(src, new_bmap); 225 if (retval) { 226 ext2fs_free_mem(&new_bmap->description); 227 ext2fs_free_mem(&new_bmap); 228 return retval; 229 } 230 231 *dest = new_bmap; 232 233 return 0; 234} 235 236errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap bmap, 237 __u64 new_end, 238 __u64 new_real_end) 239{ 240 if (!bmap) 241 return EINVAL; 242 243 if (EXT2FS_IS_32_BITMAP(bmap)) 244 return ext2fs_resize_generic_bitmap(bmap->magic, new_end, 245 new_real_end, bmap); 246 247 if (!EXT2FS_IS_64_BITMAP(bmap)) 248 return EINVAL; 249 250 return bmap->bitmap_ops->resize_bmap(bmap, new_end, new_real_end); 251} 252 253errcode_t ext2fs_fudge_generic_bmap_end(ext2fs_generic_bitmap bitmap, 254 errcode_t neq, 255 __u64 end, __u64 *oend) 256{ 257 if (!bitmap) 258 return EINVAL; 259 260 if (EXT2FS_IS_32_BITMAP(bitmap)) { 261 ext2_ino_t tmp_oend; 262 int retval; 263 264 retval = ext2fs_fudge_generic_bitmap_end(bitmap, bitmap->magic, 265 neq, end, &tmp_oend); 266 if (oend) 267 *oend = tmp_oend; 268 return retval; 269 } 270 271 if (!EXT2FS_IS_64_BITMAP(bitmap)) 272 return EINVAL; 273 274 if (end > bitmap->real_end) 275 return neq; 276 if (oend) 277 *oend = bitmap->end; 278 bitmap->end = end; 279 return 0; 280} 281 282__u64 ext2fs_get_generic_bmap_start(ext2fs_generic_bitmap bitmap) 283{ 284 if (!bitmap) 285 return EINVAL; 286 287 if (EXT2FS_IS_32_BITMAP(bitmap)) 288 return ext2fs_get_generic_bitmap_start(bitmap); 289 290 if (!EXT2FS_IS_64_BITMAP(bitmap)) 291 return EINVAL; 292 293 return bitmap->start; 294} 295 296__u64 ext2fs_get_generic_bmap_end(ext2fs_generic_bitmap bitmap) 297{ 298 if (!bitmap) 299 return EINVAL; 300 301 if (EXT2FS_IS_32_BITMAP(bitmap)) 302 return ext2fs_get_generic_bitmap_end(bitmap); 303 304 if (!EXT2FS_IS_64_BITMAP(bitmap)) 305 return EINVAL; 306 307 return bitmap->end; 308} 309 310void ext2fs_clear_generic_bmap(ext2fs_generic_bitmap bitmap) 311{ 312 if (EXT2FS_IS_32_BITMAP(bitmap)) 313 ext2fs_clear_generic_bitmap(bitmap); 314 else 315 bitmap->bitmap_ops->clear_bmap (bitmap); 316} 317 318int ext2fs_mark_generic_bmap(ext2fs_generic_bitmap bitmap, 319 __u64 arg) 320{ 321 if (!bitmap) 322 return 0; 323 324 if (EXT2FS_IS_32_BITMAP(bitmap)) { 325 if (arg & ~0xffffffffULL) { 326 ext2fs_warn_bitmap2(bitmap, 327 EXT2FS_MARK_ERROR, 0xffffffff); 328 return 0; 329 } 330 return ext2fs_mark_generic_bitmap(bitmap, arg); 331 } 332 333 if (!EXT2FS_IS_64_BITMAP(bitmap)) 334 return 0; 335 336 arg >>= bitmap->cluster_bits; 337 338 if ((arg < bitmap->start) || (arg > bitmap->end)) { 339 warn_bitmap(bitmap, EXT2FS_MARK_ERROR, arg); 340 return 0; 341 } 342 343 return bitmap->bitmap_ops->mark_bmap(bitmap, arg); 344} 345 346int ext2fs_unmark_generic_bmap(ext2fs_generic_bitmap bitmap, 347 __u64 arg) 348{ 349 if (!bitmap) 350 return 0; 351 352 if (EXT2FS_IS_32_BITMAP(bitmap)) { 353 if (arg & ~0xffffffffULL) { 354 ext2fs_warn_bitmap2(bitmap, EXT2FS_UNMARK_ERROR, 355 0xffffffff); 356 return 0; 357 } 358 return ext2fs_unmark_generic_bitmap(bitmap, arg); 359 } 360 361 if (!EXT2FS_IS_64_BITMAP(bitmap)) 362 return 0; 363 364 arg >>= bitmap->cluster_bits; 365 366 if ((arg < bitmap->start) || (arg > bitmap->end)) { 367 warn_bitmap(bitmap, EXT2FS_UNMARK_ERROR, arg); 368 return 0; 369 } 370 371 return bitmap->bitmap_ops->unmark_bmap(bitmap, arg); 372} 373 374int ext2fs_test_generic_bmap(ext2fs_generic_bitmap bitmap, 375 __u64 arg) 376{ 377 if (!bitmap) 378 return 0; 379 380 if (EXT2FS_IS_32_BITMAP(bitmap)) { 381 if (arg & ~0xffffffffULL) { 382 ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, 383 0xffffffff); 384 return 0; 385 } 386 return ext2fs_test_generic_bitmap(bitmap, arg); 387 } 388 389 if (!EXT2FS_IS_64_BITMAP(bitmap)) 390 return 0; 391 392 arg >>= bitmap->cluster_bits; 393 394 if ((arg < bitmap->start) || (arg > bitmap->end)) { 395 warn_bitmap(bitmap, EXT2FS_TEST_ERROR, arg); 396 return 0; 397 } 398 399 return bitmap->bitmap_ops->test_bmap(bitmap, arg); 400} 401 402errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap bmap, 403 __u64 start, unsigned int num, 404 void *in) 405{ 406 if (!bmap) 407 return EINVAL; 408 409 if (EXT2FS_IS_32_BITMAP(bmap)) { 410 if ((start+num-1) & ~0xffffffffULL) { 411 ext2fs_warn_bitmap2(bmap, EXT2FS_UNMARK_ERROR, 412 0xffffffff); 413 return EINVAL; 414 } 415 return ext2fs_set_generic_bitmap_range(bmap, bmap->magic, 416 start, num, in); 417 } 418 419 if (!EXT2FS_IS_64_BITMAP(bmap)) 420 return EINVAL; 421 422 return bmap->bitmap_ops->set_bmap_range(bmap, start, num, in); 423} 424 425errcode_t ext2fs_get_generic_bmap_range(ext2fs_generic_bitmap bmap, 426 __u64 start, unsigned int num, 427 void *out) 428{ 429 if (!bmap) 430 return EINVAL; 431 432 if (EXT2FS_IS_32_BITMAP(bmap)) { 433 if ((start+num-1) & ~0xffffffffULL) { 434 ext2fs_warn_bitmap2(bmap, 435 EXT2FS_UNMARK_ERROR, 0xffffffff); 436 return EINVAL; 437 } 438 return ext2fs_get_generic_bitmap_range(bmap, bmap->magic, 439 start, num, out); 440 } 441 442 if (!EXT2FS_IS_64_BITMAP(bmap)) 443 return EINVAL; 444 445 return bmap->bitmap_ops->get_bmap_range(bmap, start, num, out); 446} 447 448errcode_t ext2fs_compare_generic_bmap(errcode_t neq, 449 ext2fs_generic_bitmap bm1, 450 ext2fs_generic_bitmap bm2) 451{ 452 blk64_t i; 453 454 if (!bm1 || !bm2) 455 return EINVAL; 456 if (bm1->magic != bm2->magic) 457 return EINVAL; 458 459 /* Now we know both bitmaps have the same magic */ 460 if (EXT2FS_IS_32_BITMAP(bm1)) 461 return ext2fs_compare_generic_bitmap(bm1->magic, neq, bm1, bm2); 462 463 if (!EXT2FS_IS_64_BITMAP(bm1)) 464 return EINVAL; 465 466 if ((bm1->start != bm2->start) || 467 (bm1->end != bm2->end)) 468 return neq; 469 470 for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++) 471 if (ext2fs_test_generic_bmap(bm1, i) != 472 ext2fs_test_generic_bmap(bm2, i)) 473 return neq; 474 475 return 0; 476} 477 478void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap bmap) 479{ 480 __u64 start, num; 481 482 if (EXT2FS_IS_32_BITMAP(bmap)) { 483 ext2fs_set_generic_bitmap_padding(bmap); 484 return; 485 } 486 487 start = bmap->end + 1; 488 num = bmap->real_end - bmap->end; 489 bmap->bitmap_ops->mark_bmap_extent(bmap, start, num); 490 /* XXX ought to warn on error */ 491} 492 493int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap bmap, 494 blk64_t block, unsigned int num) 495{ 496 if (!bmap) 497 return EINVAL; 498 499 if (num == 1) 500 return !ext2fs_test_generic_bmap((ext2fs_generic_bitmap) 501 bmap, block); 502 503 if (EXT2FS_IS_32_BITMAP(bmap)) { 504 if ((block+num-1) & ~0xffffffffULL) { 505 ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap, 506 EXT2FS_UNMARK_ERROR, 0xffffffff); 507 return EINVAL; 508 } 509 return ext2fs_test_block_bitmap_range( 510 (ext2fs_generic_bitmap) bmap, block, num); 511 } 512 513 if (!EXT2FS_IS_64_BITMAP(bmap)) 514 return EINVAL; 515 516 return bmap->bitmap_ops->test_clear_bmap_extent(bmap, block, num); 517} 518 519void ext2fs_mark_block_bitmap_range2(ext2fs_block_bitmap bmap, 520 blk64_t block, unsigned int num) 521{ 522 if (!bmap) 523 return; 524 525 if (EXT2FS_IS_32_BITMAP(bmap)) { 526 if ((block+num-1) & ~0xffffffffULL) { 527 ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap, 528 EXT2FS_UNMARK_ERROR, 0xffffffff); 529 return; 530 } 531 ext2fs_mark_block_bitmap_range((ext2fs_generic_bitmap) bmap, 532 block, num); 533 } 534 535 if (!EXT2FS_IS_64_BITMAP(bmap)) 536 return; 537 538 if ((block < bmap->start) || (block+num-1 > bmap->end)) { 539 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block, 540 bmap->description); 541 return; 542 } 543 544 bmap->bitmap_ops->mark_bmap_extent(bmap, block, num); 545} 546 547void ext2fs_unmark_block_bitmap_range2(ext2fs_block_bitmap bmap, 548 blk64_t block, unsigned int num) 549{ 550 if (!bmap) 551 return; 552 553 if (EXT2FS_IS_32_BITMAP(bmap)) { 554 if ((block+num-1) & ~0xffffffffULL) { 555 ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap, 556 EXT2FS_UNMARK_ERROR, 0xffffffff); 557 return; 558 } 559 ext2fs_unmark_block_bitmap_range((ext2fs_generic_bitmap) bmap, 560 block, num); 561 } 562 563 if (!EXT2FS_IS_64_BITMAP(bmap)) 564 return; 565 566 if ((block < bmap->start) || (block+num-1 > bmap->end)) { 567 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block, 568 bmap->description); 569 return; 570 } 571 572 bmap->bitmap_ops->unmark_bmap_extent(bmap, block, num); 573} 574 575void ext2fs_warn_bitmap32(ext2fs_generic_bitmap bitmap, const char *func) 576{ 577#ifndef OMIT_COM_ERR 578 if (bitmap && bitmap->description) 579 com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, 580 "called %s with 64-bit bitmap for %s", func, 581 bitmap->description); 582 else 583 com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, 584 "called %s with 64-bit bitmap", func); 585#endif 586} 587 588errcode_t ext2fs_convert_subcluster_bitmap(ext2_filsys fs, 589 ext2fs_block_bitmap *bitmap) 590{ 591 ext2fs_block_bitmap cmap, bmap; 592 errcode_t retval; 593 blk64_t i, b_end, c_end; 594 int n, ratio; 595 596 bmap = *bitmap; 597 598 if (fs->cluster_ratio_bits == ext2fs_get_bitmap_granularity(bmap)) 599 return 0; /* Nothing to do */ 600 601 retval = ext2fs_allocate_block_bitmap(fs, "converted cluster bitmap", 602 &cmap); 603 if (retval) 604 return retval; 605 606 i = bmap->start; 607 b_end = bmap->end; 608 bmap->end = bmap->real_end; 609 c_end = cmap->end; 610 cmap->end = cmap->real_end; 611 n = 0; 612 ratio = 1 << fs->cluster_ratio_bits; 613 while (i < bmap->real_end) { 614 if (ext2fs_test_block_bitmap2(bmap, i)) { 615 ext2fs_mark_block_bitmap2(cmap, i); 616 i += ratio - n; 617 n = 0; 618 continue; 619 } 620 i++; n++; 621 if (n >= ratio) 622 n = 0; 623 } 624 bmap->end = b_end; 625 cmap->end = c_end; 626 ext2fs_free_block_bitmap(bmap); 627 *bitmap = cmap; 628 return 0; 629} 630