gen_bitmap64.c revision 67861e5bf3ae177b14d34846218fcdfdeee805a6
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 errcode_t retval; 90 91 if (!type) 92 type = EXT2FS_BMAP64_BITARRAY; 93 94 switch (type) { 95 case EXT2FS_BMAP64_BITARRAY: 96 ops = &ext2fs_blkmap64_bitarray; 97 break; 98 default: 99 return EINVAL; 100 } 101 102 retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap), 103 &bitmap); 104 if (retval) 105 return retval; 106 107 /* XXX factor out, repeated in copy_bmap */ 108 bitmap->magic = magic; 109 bitmap->fs = fs; 110 bitmap->start = start; 111 bitmap->end = end; 112 bitmap->real_end = real_end; 113 bitmap->bitmap_ops = ops; 114 bitmap->cluster_bits = 0; 115 switch (magic) { 116 case EXT2_ET_MAGIC_INODE_BITMAP64: 117 bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK; 118 break; 119 case EXT2_ET_MAGIC_BLOCK_BITMAP64: 120 bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK; 121 bitmap->cluster_bits = fs->cluster_ratio_bits; 122 break; 123 default: 124 bitmap->base_error_code = EXT2_ET_BAD_GENERIC_MARK; 125 } 126 if (descr) { 127 retval = ext2fs_get_mem(strlen(descr)+1, &bitmap->description); 128 if (retval) { 129 ext2fs_free_mem(&bitmap); 130 return retval; 131 } 132 strcpy(bitmap->description, descr); 133 } else 134 bitmap->description = 0; 135 136 retval = bitmap->bitmap_ops->new_bmap(fs, bitmap); 137 if (retval) { 138 ext2fs_free_mem(&bitmap->description); 139 ext2fs_free_mem(&bitmap); 140 return retval; 141 } 142 143 *ret = bitmap; 144 return 0; 145} 146 147void ext2fs_free_generic_bmap(ext2fs_generic_bitmap bmap) 148{ 149 if (!bmap) 150 return; 151 152 if (EXT2FS_IS_32_BITMAP(bmap)) { 153 ext2fs_free_generic_bitmap(bmap); 154 return; 155 } 156 157 if (!EXT2FS_IS_64_BITMAP(bmap)) 158 return; 159 160 bmap->bitmap_ops->free_bmap(bmap); 161 162 if (bmap->description) { 163 ext2fs_free_mem(&bmap->description); 164 bmap->description = 0; 165 } 166 bmap->magic = 0; 167 ext2fs_free_mem(&bmap); 168} 169 170errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap src, 171 ext2fs_generic_bitmap *dest) 172{ 173 char *descr, *new_descr; 174 ext2fs_generic_bitmap new_bmap; 175 errcode_t retval; 176 177 if (!src) 178 return EINVAL; 179 180 if (EXT2FS_IS_32_BITMAP(src)) 181 return ext2fs_copy_generic_bitmap(src, dest); 182 183 if (!EXT2FS_IS_64_BITMAP(src)) 184 return EINVAL; 185 186 /* Allocate a new bitmap struct */ 187 retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap), 188 &new_bmap); 189 if (retval) 190 return retval; 191 192 /* Copy all the high-level parts over */ 193 new_bmap->magic = src->magic; 194 new_bmap->fs = src->fs; 195 new_bmap->start = src->start; 196 new_bmap->end = src->end; 197 new_bmap->real_end = src->real_end; 198 new_bmap->bitmap_ops = src->bitmap_ops; 199 new_bmap->base_error_code = src->base_error_code; 200 new_bmap->cluster_bits = src->cluster_bits; 201 202 descr = src->description; 203 if (descr) { 204 retval = ext2fs_get_mem(strlen(descr)+1, &new_descr); 205 if (retval) { 206 ext2fs_free_mem(&new_bmap); 207 return retval; 208 } 209 strcpy(new_descr, descr); 210 new_bmap->description = new_descr; 211 } 212 213 retval = src->bitmap_ops->copy_bmap(src, new_bmap); 214 if (retval) { 215 ext2fs_free_mem(&new_bmap->description); 216 ext2fs_free_mem(&new_bmap); 217 return retval; 218 } 219 220 *dest = new_bmap; 221 222 return 0; 223} 224 225errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap bmap, 226 __u64 new_end, 227 __u64 new_real_end) 228{ 229 if (!bmap) 230 return EINVAL; 231 232 if (EXT2FS_IS_32_BITMAP(bmap)) 233 return ext2fs_resize_generic_bitmap(bmap->magic, new_end, 234 new_real_end, bmap); 235 236 if (!EXT2FS_IS_64_BITMAP(bmap)) 237 return EINVAL; 238 239 return bmap->bitmap_ops->resize_bmap(bmap, new_end, new_real_end); 240} 241 242errcode_t ext2fs_fudge_generic_bmap_end(ext2fs_generic_bitmap bitmap, 243 errcode_t neq, 244 __u64 end, __u64 *oend) 245{ 246 if (!bitmap) 247 return EINVAL; 248 249 if (EXT2FS_IS_32_BITMAP(bitmap)) { 250 ext2_ino_t tmp_oend; 251 int retval; 252 253 retval = ext2fs_fudge_generic_bitmap_end(bitmap, bitmap->magic, 254 neq, end, &tmp_oend); 255 if (oend) 256 *oend = tmp_oend; 257 return retval; 258 } 259 260 if (!EXT2FS_IS_64_BITMAP(bitmap)) 261 return EINVAL; 262 263 if (end > bitmap->real_end) 264 return neq; 265 if (oend) 266 *oend = bitmap->end; 267 bitmap->end = end; 268 return 0; 269} 270 271__u64 ext2fs_get_generic_bmap_start(ext2fs_generic_bitmap bitmap) 272{ 273 if (!bitmap) 274 return EINVAL; 275 276 if (EXT2FS_IS_32_BITMAP(bitmap)) 277 return ext2fs_get_generic_bitmap_start(bitmap); 278 279 if (!EXT2FS_IS_64_BITMAP(bitmap)) 280 return EINVAL; 281 282 return bitmap->start; 283} 284 285__u64 ext2fs_get_generic_bmap_end(ext2fs_generic_bitmap bitmap) 286{ 287 if (!bitmap) 288 return EINVAL; 289 290 if (EXT2FS_IS_32_BITMAP(bitmap)) 291 return ext2fs_get_generic_bitmap_end(bitmap); 292 293 if (!EXT2FS_IS_64_BITMAP(bitmap)) 294 return EINVAL; 295 296 return bitmap->end; 297} 298 299void ext2fs_clear_generic_bmap(ext2fs_generic_bitmap bitmap) 300{ 301 if (EXT2FS_IS_32_BITMAP(bitmap)) 302 ext2fs_clear_generic_bitmap(bitmap); 303 else 304 bitmap->bitmap_ops->clear_bmap (bitmap); 305} 306 307int ext2fs_mark_generic_bmap(ext2fs_generic_bitmap bitmap, 308 __u64 arg) 309{ 310 if (!bitmap) 311 return 0; 312 313 if (EXT2FS_IS_32_BITMAP(bitmap)) { 314 if (arg & ~0xffffffffULL) { 315 ext2fs_warn_bitmap2(bitmap, 316 EXT2FS_MARK_ERROR, 0xffffffff); 317 return 0; 318 } 319 return ext2fs_mark_generic_bitmap(bitmap, arg); 320 } 321 322 if (!EXT2FS_IS_64_BITMAP(bitmap)) 323 return 0; 324 325 arg >>= bitmap->cluster_bits; 326 327 if ((arg < bitmap->start) || (arg > bitmap->end)) { 328 warn_bitmap(bitmap, EXT2FS_MARK_ERROR, arg); 329 return 0; 330 } 331 332 return bitmap->bitmap_ops->mark_bmap(bitmap, arg); 333} 334 335int ext2fs_unmark_generic_bmap(ext2fs_generic_bitmap bitmap, 336 __u64 arg) 337{ 338 if (!bitmap) 339 return 0; 340 341 if (EXT2FS_IS_32_BITMAP(bitmap)) { 342 if (arg & ~0xffffffffULL) { 343 ext2fs_warn_bitmap2(bitmap, EXT2FS_UNMARK_ERROR, 344 0xffffffff); 345 return 0; 346 } 347 return ext2fs_unmark_generic_bitmap(bitmap, arg); 348 } 349 350 if (!EXT2FS_IS_64_BITMAP(bitmap)) 351 return 0; 352 353 arg >>= bitmap->cluster_bits; 354 355 if ((arg < bitmap->start) || (arg > bitmap->end)) { 356 warn_bitmap(bitmap, EXT2FS_UNMARK_ERROR, arg); 357 return 0; 358 } 359 360 return bitmap->bitmap_ops->unmark_bmap(bitmap, arg); 361} 362 363int ext2fs_test_generic_bmap(ext2fs_generic_bitmap bitmap, 364 __u64 arg) 365{ 366 if (!bitmap) 367 return 0; 368 369 if (EXT2FS_IS_32_BITMAP(bitmap)) { 370 if (arg & ~0xffffffffULL) { 371 ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, 372 0xffffffff); 373 return 0; 374 } 375 return ext2fs_test_generic_bitmap(bitmap, arg); 376 } 377 378 if (!EXT2FS_IS_64_BITMAP(bitmap)) 379 return 0; 380 381 arg >>= bitmap->cluster_bits; 382 383 if ((arg < bitmap->start) || (arg > bitmap->end)) { 384 warn_bitmap(bitmap, EXT2FS_TEST_ERROR, arg); 385 return 0; 386 } 387 388 return bitmap->bitmap_ops->test_bmap(bitmap, arg); 389} 390 391errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap bmap, 392 __u64 start, unsigned int num, 393 void *in) 394{ 395 if (!bmap) 396 return EINVAL; 397 398 if (EXT2FS_IS_32_BITMAP(bmap)) { 399 if ((start+num-1) & ~0xffffffffULL) { 400 ext2fs_warn_bitmap2(bmap, EXT2FS_UNMARK_ERROR, 401 0xffffffff); 402 return EINVAL; 403 } 404 return ext2fs_set_generic_bitmap_range(bmap, bmap->magic, 405 start, num, in); 406 } 407 408 if (!EXT2FS_IS_64_BITMAP(bmap)) 409 return EINVAL; 410 411 return bmap->bitmap_ops->set_bmap_range(bmap, start, num, in); 412} 413 414errcode_t ext2fs_get_generic_bmap_range(ext2fs_generic_bitmap bmap, 415 __u64 start, unsigned int num, 416 void *out) 417{ 418 if (!bmap) 419 return EINVAL; 420 421 if (EXT2FS_IS_32_BITMAP(bmap)) { 422 if ((start+num-1) & ~0xffffffffULL) { 423 ext2fs_warn_bitmap2(bmap, 424 EXT2FS_UNMARK_ERROR, 0xffffffff); 425 return EINVAL; 426 } 427 return ext2fs_get_generic_bitmap_range(bmap, bmap->magic, 428 start, num, out); 429 } 430 431 if (!EXT2FS_IS_64_BITMAP(bmap)) 432 return EINVAL; 433 434 return bmap->bitmap_ops->get_bmap_range(bmap, start, num, out); 435} 436 437errcode_t ext2fs_compare_generic_bmap(errcode_t neq, 438 ext2fs_generic_bitmap bm1, 439 ext2fs_generic_bitmap bm2) 440{ 441 blk64_t i; 442 443 if (!bm1 || !bm2) 444 return EINVAL; 445 if (bm1->magic != bm2->magic) 446 return EINVAL; 447 448 /* Now we know both bitmaps have the same magic */ 449 if (EXT2FS_IS_32_BITMAP(bm1)) 450 return ext2fs_compare_generic_bitmap(bm1->magic, neq, bm1, bm2); 451 452 if (!EXT2FS_IS_64_BITMAP(bm1)) 453 return EINVAL; 454 455 if ((bm1->start != bm2->start) || 456 (bm1->end != bm2->end)) 457 return neq; 458 459 for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++) 460 if (ext2fs_test_generic_bmap(bm1, i) != 461 ext2fs_test_generic_bmap(bm2, i)) 462 return neq; 463 464 return 0; 465} 466 467void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap bmap) 468{ 469 __u64 start, num; 470 471 if (EXT2FS_IS_32_BITMAP(bmap)) { 472 ext2fs_set_generic_bitmap_padding(bmap); 473 return; 474 } 475 476 start = bmap->end + 1; 477 num = bmap->real_end - bmap->end; 478 bmap->bitmap_ops->mark_bmap_extent(bmap, start, num); 479 /* XXX ought to warn on error */ 480} 481 482int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap bmap, 483 blk64_t block, unsigned int num) 484{ 485 if (!bmap) 486 return EINVAL; 487 488 if (num == 1) 489 return !ext2fs_test_generic_bmap((ext2fs_generic_bitmap) 490 bmap, block); 491 492 if (EXT2FS_IS_32_BITMAP(bmap)) { 493 if ((block+num-1) & ~0xffffffffULL) { 494 ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap, 495 EXT2FS_UNMARK_ERROR, 0xffffffff); 496 return EINVAL; 497 } 498 return ext2fs_test_block_bitmap_range( 499 (ext2fs_generic_bitmap) bmap, block, num); 500 } 501 502 if (!EXT2FS_IS_64_BITMAP(bmap)) 503 return EINVAL; 504 505 return bmap->bitmap_ops->test_clear_bmap_extent(bmap, block, num); 506} 507 508void ext2fs_mark_block_bitmap_range2(ext2fs_block_bitmap bmap, 509 blk64_t block, unsigned int num) 510{ 511 if (!bmap) 512 return; 513 514 if (EXT2FS_IS_32_BITMAP(bmap)) { 515 if ((block+num-1) & ~0xffffffffULL) { 516 ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap, 517 EXT2FS_UNMARK_ERROR, 0xffffffff); 518 return; 519 } 520 ext2fs_mark_block_bitmap_range((ext2fs_generic_bitmap) bmap, 521 block, num); 522 } 523 524 if (!EXT2FS_IS_64_BITMAP(bmap)) 525 return; 526 527 if ((block < bmap->start) || (block+num-1 > bmap->end)) { 528 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block, 529 bmap->description); 530 return; 531 } 532 533 bmap->bitmap_ops->mark_bmap_extent(bmap, block, num); 534} 535 536void ext2fs_unmark_block_bitmap_range2(ext2fs_block_bitmap bmap, 537 blk64_t block, unsigned int num) 538{ 539 if (!bmap) 540 return; 541 542 if (EXT2FS_IS_32_BITMAP(bmap)) { 543 if ((block+num-1) & ~0xffffffffULL) { 544 ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap, 545 EXT2FS_UNMARK_ERROR, 0xffffffff); 546 return; 547 } 548 ext2fs_unmark_block_bitmap_range((ext2fs_generic_bitmap) bmap, 549 block, num); 550 } 551 552 if (!EXT2FS_IS_64_BITMAP(bmap)) 553 return; 554 555 if ((block < bmap->start) || (block+num-1 > bmap->end)) { 556 ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block, 557 bmap->description); 558 return; 559 } 560 561 bmap->bitmap_ops->unmark_bmap_extent(bmap, block, num); 562} 563 564void ext2fs_warn_bitmap32(ext2fs_generic_bitmap bitmap, const char *func) 565{ 566#ifndef OMIT_COM_ERR 567 if (bitmap && bitmap->description) 568 com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, 569 "called %s with 64-bit bitmap for %s", func, 570 bitmap->description); 571 else 572 com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP, 573 "called %s with 64-bit bitmap", func); 574#endif 575} 576 577errcode_t ext2fs_convert_subcluster_bitmap(ext2_filsys fs, 578 ext2fs_block_bitmap *bitmap) 579{ 580 ext2fs_block_bitmap cmap, bmap; 581 errcode_t retval; 582 blk64_t i, b_end, c_end; 583 int n, ratio; 584 585 bmap = *bitmap; 586 587 if (fs->cluster_ratio_bits == ext2fs_get_bitmap_granularity(bmap)) 588 return 0; /* Nothing to do */ 589 590 retval = ext2fs_allocate_block_bitmap(fs, "converted cluster bitmap", 591 &cmap); 592 if (retval) 593 return retval; 594 595 i = bmap->start; 596 b_end = bmap->end; 597 bmap->end = bmap->real_end; 598 c_end = cmap->end; 599 cmap->end = cmap->real_end; 600 n = 0; 601 ratio = 1 << fs->cluster_ratio_bits; 602 while (i < bmap->real_end) { 603 if (ext2fs_test_block_bitmap2(bmap, i)) { 604 ext2fs_mark_block_bitmap2(cmap, i); 605 i += ratio - n; 606 n = 0; 607 continue; 608 } 609 i++; n++; 610 if (n >= ratio) 611 n = 0; 612 } 613 bmap->end = b_end; 614 cmap->end = c_end; 615 ext2fs_free_block_bitmap(bmap); 616 *bitmap = cmap; 617 return 0; 618} 619