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